I have a router-view that needs to be reloaded after sending some POST requests and receiving whether the operation was successful, but
this.$route.router.go(this.$route.path)
doesn't trigger a reload even if the component's route.canReuse is set to false.
Now I can only do
created.apply(this) // `created` is the life-cycle hook function for the component
in the ajax callback to force the router-view to update itself, which is cumbersome.
Perhaps something like $route.router.reload() would be great, as it would be the counterpart of location.reload().
Lacking a reload method also prevents me from putting request promises in component.route.data() because it's only triggered when route path changes... If I do so, I'd have to write the same request promises again in another reload method..
Having a reload route method would be nice.
i think so ~~ Having a reload route method would be nice.
having a force re-render on a specific v-for item would be even better
@fnlctrl can you please elaborate in detail on your particular use case for this feature? I'm finding it difficult to reason why the entire router-view needs to be reloaded based on a status of a POST request.
Here's what I think: after the POST request, what you really want to do is not reloading the component, but rather re-fetch the data. However you have placed the data-fetching logic in your component's lifecycle hooks, but that doesn't have to be the case. Consider:
export default {
created () {
this.fetchData()
},
methods: {
fetchData () {
// fetch data
}
}
}
After the POST request is resolved, you simply call this.fetchData() to re-fetch. Reloading the entire component is doing more than necessary, since it leads to a full re-render of the DOM as well.
@yyx990803 No that's not what I meant..
I just want to reload the route, and the component is reused (route.canReuse is true), so nothing is changed except for it's route.data() called again. No expensive dom operations. (I really want to use route.data because it's so elegant).
Consider this.
route: {
data: ({to: {params: {someParam}}}) => ({
foo: $.get('/path/to/resource', {someParam}),
})
}
Now, without a reload method, I will have to write$.get('/path/to/resource', {someParam}) again in fetchData..
It's like when it transitions from /a/1 to /a/2, the component is reused, only the route.data() is fired again.
Now I just want the same thing to happen when transitioning from /a/1 to /a/1 (explicitly, with a reload method).
Hmm that makes sense, maybe a $reloadRouteData() method?
Looks good!
Well, since canReuse is about to be deprecated and every component will be reusable (https://github.com/vuejs/vue-router/issues/321), I think $reload would suffice since nothing else will be fired again except for route.data()?
On another thought, it might be more straightforward to just add an additional option to router.go:
router.go({
path: '/a/1',
force: true
})
Then it will force the router to match the route even if it is the same with current route, and because all current components can be reused, only data hooks will re-run.
@yyx990803 In addition to the force option, would it make sense to add a $reload function that simply calls router.go with the correct arguments? The router.go call doesn't intuitively read as a reload operation to me.
Adding both would be nice, but in what scenario other than reloading would I use force option?
@coulix did you try data hook?
I have a use case for this, and it was already mentioned by @liudangyi: https://github.com/vuejs/vue-router/issues/311#issuecomment-170488849
Another reason why I need a "refresh" function: we use a beforeEach hook to check authentication. When a user logs in / logs out, we need to trigger this hook again to make sure he has the right to see this page.
any news about the force option ? :)
Also interested in this feature.
+1 for this feature too.
+1 this feature!!!
I would love this feature too!
force: true would be useful :)
+1 this feature!!! It sounds like there is something like this already in place??? Can someone please confirm if that is the case. Thanks!
+1
Why so long? :(
@happierall The author is busy :D
You can use
$router.go({
path: $router.path,
query: {
t: + new Date()
}
})
for now, to simulate a reload
@fnlctrl wow! Totally awesome solution!
Thank you.
@yyx990803 After reading the release notes and code examples of 2.0.0b1, I found that it's still not possible to trigger a data reload while keeping the same route params (in the example, by using a watcher on $route). Would you suggest a way to do it properly without using workarounds like adding a timestamp on queries?
@fnlctrl I actually looked at this issue when working on 2.0, but found the reasoning behind this feature questionable. After all what you really want to do is still "refresh the data" rather than "re-trigger the hooks". In 2.0 there's no longer the data hook, there are only navigation guard hooks now, so re-triggering navigation hooks without an actual navigation just feels wrong. In terms of data fetching this is what you'd typically do:
created () {
this.fetchData()
},
watch: {
'$route': 'fetchData'
},
methods: {
fetchData () { ... }
}
So instead of reload, you call fetchData again when you want to refresh the data. This is indeed a bit more verbose than using the data hook, but everything is more explicit.
In fact, you can write a mixin/plugin to do the following:
beforeCreated, look for this.$options.fetchRouteDatacreated hook / $route watch callback$reloadRouteData that simply calls this function again.You can even make it accept a returned Promise, like the old data hook. But in general, I want to keep the 2.0 interface as minimal as possible and leave more to the userland.
@yyx990803 Thanks :+1: ! Will write a plugin to do that.
@yyx990803 Thanks for the explanation. As an aside, what would be the recommended way to show a 404 page (or similar) based on the result from fetchData (e.g. if a resource doesn't exist based on the param ID)? I've never really known the best way to maintain the URL but show a generic 404 page from the route data.
@dcgauld have a dedicated UI component that contains 404 content, and conditionally show it after the loading spinner if the data is missing.
For anyone who's interested, I've implemented a plugin according to [https://github.com/vuejs/vue-router/issues/296#issuecomment-235481643]. It supports both vue 1 and 2, and was used for the migration of our production app from vue/vue-router 1 to 2.
Some migration tips:
route.data to fetchRouteData in component options, and $route will be passed in (so no more transition objects). this.$setAsyncData.$loadingRouteData is implemented, but you need to define it in component's data option first.this.$reloadRouteData if you need to reload. This answers for the original feature request.// 1.0
{
route: {
data({to: {params: {foo, bar}}}) {
return {promise1, promise2}
}
}
}
// With this plugin, 1.0 or 2.0
{
fetchRouteData({params: {foo, bar}}) {
return this.$setAsyncData({promise1, promise2})
}
}
// Async/await
{
async fetchRouteData({params: {foo, bar}}) {
this.foo = await promise;
}
}
So I'm closing this issue for now.
Ensuring form (validation) and $data reset, I wrote the following code:
created () {
this.fetchForm()
},
watch: {
$route (data, oldData) {
this.reInit()
},
// ...
},
methods: {
reInit () {
const data = this.$options.data.call(this)
Object.assign(this, data)
this.$nextTick(() => {
this.$refs.form.resetFields()
this.fetchForm()
})
},
// ...
}
:+1: just been told about another solution:
https://forum-archive.vuejs.org/topic/4840/keep-canreuse-in-vue-router-2-0
You simply add a key attribute to the
<router-view :key="$route.path"></router-view>
Like this:
<router-link :to="$route.path + '?_=' + (new Date).getTime()">
refresh
</router-link>
@fnlctrl thks, your method worked, but it will refresh the whole page where what i want is just refresh/reload the component mounted to the router-view. like this one. #397
I find a method to resolve it.
// replace another route (with different component or a dead route) at first
vm.$router.replace({
path: '/_empty',
})
//then replace your route (with same component)
vm.$router.replace({
path: '/student/report',
query: {
'paperId':paperId
}
})
When I switch users to login, and I use the 'keep-alive', so I really want to reload the whole page to clear the cache. So how can I do? (求尤大大解答)
Reload is useful when you may need to trigger route guards. For example say that within a page the user logged out and he/she is in the current page A. A may be allowed for guests but it may be restricted to logged users only. That's why with a refresh on page A, the route guard on A would trigger the redirect to the homepage or login page.
Really need a reload feature. I have been torturing by the problem these days.
@huziyang410 you can use
location.reload()
@Joshwoooooooooooooooooooooooooooooooong
But this method dosen`t support page jumps.
'Joshwoooooooooooooooooooooooooooooooong'.length
>> 39
@Joshwoooooooooooooooooooooooooooooooong
how use that please full example
what is my problem encountered is that i initialize my data with the property 'data',and i what to rerender them,how can i do
Use v-if to control the router-view to implement a reload method in the root component APP.vue
<template>
<router-view v-if="isRouterAlive"/>
</template>
<script>
export default {
data () {
return {
isRouterAlive: true
}
},
methods: {
reload () {
this.isRouterAlive = false
this.$nextTick(() => (this.isRouterAlive = true))
}
}
}
</script>
Then any other want to refresh their own routing page, you can do this:
this.$root.reload()
If the $root is not router container,please use provide / inject to do this.知乎上我写了个完整版本的
VueRouter.prototype.reload = ->
history = @history
current = history.current
history.updateRoute {matched:[], path:""}
@replace current
return
I like the above solution! +1
It would make sense to add this also to router-link. In our case it's useful to perform some action (like hide dropdown) if route changes using watch: $route. This doesn't work if router route is already active and I would like to avoid additional ifs
My solution to refresh the component without reloading the url:
router/index.js
{
path: 'Redirect/:path',
name: 'Redirect',
component: Redirect,
meta: { requiresAuth: true },
},
components/shared/Redirect.vue
export default {
beforeCreate() {
const path = this.$route.params.path;
this.$router.push('/');
this.$router.push(path);
},
};
The action that trigger the refresh:
this.$router.push(Redirect${this.$route.path});
watch: {
$route (data, oldData) {
this.reInit()
},
// ...
},
that watch not call
in vue-router3.0, it's work.
this.$router.push({
name: 'path_key',
query: {
t: + new Date()
},
});
Here is my workaround to reload route without full page reload
var vueRouteReloader = Vue.extend(
{
template: '<div/>',
mounted: function()
{
setTimeout(function() { router.back(); }, 100);
}
});
and then just call
router.push('/reload');
this method does not reload page at all and does not change variables value and I dont have to use session storage and restore it on page reload
PS
I do use a splashscreen while walking between routes. So when I use "reload" route it seamless for users
Here's my solution, which I use for links in a header, which when clicked should load a page or refresh it (scrolling to the top) if you're already on it.
Add ?refresh to any links that you want to work like this, such as <router-link to="/path/to?refresh">click me</router-link> or router.push('/path/to?refresh')
Now in your page component add this:
beforeRouteUpdate (to, from, next) {
next() // IMPORTANT: *after* next() else the ?refresh sticks around half the time
this.checkRefresh()
},
created () {
this.checkRefresh()
},
methods: {
checkRefresh () {
// ?refresh to force refresh if clicking eg the icon/button in the header menu
// we make sure it doesn't stick around in the url bar for the user
if (this.$route.query.refresh !== undefined) {
this.loaded = false
this.$router.replace(this.$route.path)
} else {
this.fetchData()
}
},
fetchData () {
// ... anything you want to happen on create or update
}
}
那不需要重新渲染页面改怎么办?我现在有个对话列表页面,类似qq。现在每次切换回来,页面被刷新了,我现在不需要刷新,该怎么写?
I now have a conversation list page, similar to qq. Now every time I switch back, the page is refreshed. I don't need to refresh now. How to do?
here is my solution:
create a relaod.vue and give it a route name reload :
<template>
<div></div>
</template>
<script>
export default {
created() {
this.$router.push(this.$route.query.path)
}
}
</script>
then :
const path = xxx
this.$router.push({ name: 'reload', query: { path } })
the relaod.vue should be the child of the basic layout component in order to prevent the whole page refreshing.
Here is my solution to apply the refresh either while entering or leaving a page that requires a refresh. I do it like this because most of the time I require a page refresh is because I'm adding page specific content from outside of Vue (in my case via PHP) and I needed a way to get rid of it after leaving the route.
export const router = new Router({
routes: [
{
path: "/first",
name: "first",
component: First
},
{
path: "/second",
name: "second",
component: Second,
meta: {
refresh: true
}
}
]
});
router.beforeEach((to, from, next) => {
// If we are going to a page that requires a refresh
// null is used to avoid an infinite refresh loop
if (to.meta.refresh && from.name !== null) {
window.location.href = to.path;
return;
}
// If we are leaving a page that required a refresh
if (from.meta.refresh) {
window.location.href = to.path;
return;
}
next();
});
Hope it may be useful for someone.
@happierall The author is busy :D
You can use$router.go({ path: $router.path, query: { t: + new Date() } })for now, to simulate a reload
this will reload whole page
I have actually found a pretty good solution using async function
I have also axios requests in my app components and the good point is these requests don't load anymore when i'm not logged.
//all router request (load, page change...)
router.beforeEach(async(to, from, next) => {
console.log(await store.state.security.isAuthenticated);
if (to.matched.some(record => record.meta.requiresAuth)) {
// this route requires auth, check if logged in
// if not, redirect to login page.
//check auth in vuex store (also work with getters)
if (store.state.security.isAuthenticated) {
next();
} else {
next({
path:'/home',
query:{redirect:to.fullPath},//still useful when not logged in
});
await this.$router.go({
path:to.fullPath,
force:true
})
}
}else {
next(); // make sure to always call next()!
}
}
No infinite loop at all, hope i can help...
thanks :)
Reference:https://router.vuejs.org/guide/advanced/data-fetching.html#fetching-after-navigation
有一个最简单粗暴的办法解决此问题:组件的name 值设置跟路由菜单里边的 name 只有不一样,每次重新点击菜单,就好重新渲染加载api 哈哈
reload method
const route = {
path: this.$route.path.toString(),
name: this.$route.name.toString(),
query: this.deepCopy(this.$route.query),
params: this.deepCopy(this.$route.params)
}
// 重点在这
new Promise(resolve => {
this.$router.push({ path: '/' })
resolve()
}).then(() => {
this.$router.push(route)
})
deepcopy method
function deepCopy(o) {
if (o instanceof Array) {
var n = []
for (var i = 0; i < o.length; ++i) {
n[i] = this.deepCopy(o[i])
}
return n
} else if (o instanceof Object) {
var nn = {}
for (var j in o) {
nn[j] = this.deepCopy(o[j])
}
return nn
} else {
return o
}
}
we can use forms also in some cases to realod the page
Most helpful comment
Here's what I think: after the POST request, what you really want to do is not reloading the component, but rather re-fetch the data. However you have placed the data-fetching logic in your component's lifecycle hooks, but that doesn't have to be the case. Consider:
After the POST request is resolved, you simply call
this.fetchData()to re-fetch. Reloading the entire component is doing more than necessary, since it leads to a full re-render of the DOM as well.