Vue-router: How can I refresh the page after I change the router?

Created on 4 Jan 2016  ·  35Comments  ·  Source: vuejs/vue-router

In some cases, I need to remap the router after users login. But router.replace does nothing when current path is equal to target path.

Most helpful comment

Well, location.reload() would completely destroy all stored states, including WebSocket connections.

All 35 comments

I found a forceRefresh option in router.on. But it seems not implemented yet.

@liudangyi Why not just do a typical location.reload(); page refresh. And on refresh the router will also have the updated mappings.

Well, location.reload() would completely destroy all stored states, including WebSocket connections.

Perhaps consider using local storage to persist the state?

I think there is simple example using vuex in its repo.

@liudangyi It might help us help you if you provide us the bigger picture of what you are trying to accomplish with remapping the router upon user login? Specificity always helps.

For example. I want logged-in users see a dashboard on "/" but anonymous users see a welcome page on "/".

You should render different content in the same component based on login state instead of "remapping" the router.

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.

Hi @liudangyi , If you wanna update data but content in the same component. You can using watch $route.

For example:

watch: {
      '$route' (to, from) {
        if (to.path === '/promotions') {
          this.$store.dispatch('getAllPromotions')
        } else if (to.path === '/promotions/coupon') {
          this.$store.dispatch('getAllPromotions', {
            type: 'coupon'
          })
        }
      }
    }

Dispatch will update component state.

This is a closed and old issue, but I'm leaving this for people that also land on this page, like i had.

@liudangyi I had the need for something similar (for authentication atleast) and settled on the uses of areas. Every area has their own set of routes and pages. You keep a variable named 'area' inside your store, do a Vue.watch on it, and when it changes destroy the current Vue instance and create the new one for the new area. Thus, the only reason for needing the beforeEach is to check for permissions inside the authentication area, and not if they are authenticated, since its assumed they are authenticated if they are viewing the area.

+1

I ran into this issue following a similar problem.

Not being able to force a route refresh, makes it impossible to "rerun" the beforeEnter guards.
Sometimes it's useful to cause a proper route refresh, specially when the state changed that would cause beforeEnter to fail (say token was expired).

I was using this.$router.go(this.$router.currentRoute) when user change language to request the data from the server using the new locale

it's working but in Safari it's didn't run the mounted or created.
location.reload(); fixes it.

Any other hint to overcome this issue with Safari

I've came up with solution to use 2 seperate guards:

const guards = [
    waitGuard,
    authGuard,
]
guards.forEach(
    guard => router.beforeEach(guard)
)

one just checking

Meteor.loggingIn()

and if it's true it waits until value changes to false

import { Meteor } from 'meteor/meteor'

import { store } from '/imports/store'

export const waitGuard = (to, from, next) => {
    if (!Meteor.loggingIn()) { // the case of the unlogged user...
        return next()          // nothing to wait for
    }

    const unwatch = store.watch(
        () => store.getters.loggingIn,
        (value) => {
            if (value) { // insurance against lazy store
                return
            }
            unwatch()
            next()
        }
    )
}

the second guard checks authorization, it runs only after method next() without params is invoked (which happens on Meteor.loggingIn() value change or when it's the unlogged user case)

FWIW, I worked around this issue by creating a redirect page watching and storing the states coming from components and the path, which gets me back to where I was going with the states I stored in sessionStorage or localStorage

If you you agree to reload with session/localStorage, you could probably also consider splitting your app into two, one for logging-in and the second for the app. For me, only SPA solutions are in account at the moment. 👍

I found the solution, I changed [routerLink] to "href". May it can to help.

Can you provide an example phuongleduy, I'm having the same issue here...

My solution for this is to create method getData and call it when I change URL.

  computed: {
    getFullPath () {
      return this.$route.path
    }
  },
  watch: {
    getFullPath () {
      this.getData()
    }
  },
  methods: {
    getData () {
      // Call my lovely API
    }
  }

@latovicalmin Possibly a bit hacky, but it certainly does the trick. Thanks!

@latovicalmin at this time of the night I don't even care, it works like a charm! 🎉

@latovicalmin You can simplify your code a bit:

  watch: {
    '$route.path': 'getData'
  },
  methods: {
    getData () {
      // Call my lovely API
    }
  }

@liudangyi

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.

Same here. Is there a handy solution for this for today?

I use router.go(0) in onComplete callback:

this.$router.replace(
  { name: 'orgchartProj', params: { ...this.$route.params } },
  () => {
    this.$router.go(0);
  }
);

This is work for me.

I use this:
myLogoutActivity().then(this.$router.push("/logout"))
And my logout:

{
    path: '/logout',
    name: 'logout',
    beforeEnter: (to, from, next) => {
        next();
        next(from)
    }
},

I use go(0) before, but page blink

IMO this should be a supported API for the issues and popular use-case @liudangyi mentions, I only want to define my auth guard rules in one place and when I sign out I would like to re-run the route guards which handles where to navigate to.

None of the workarounds are ideal, replacing with the same route with {force:true} or even the {query: {t:+ new Date}} hack changes the route but doesn't re-run the guards, using router.go(0) does a full page reload.

The best solution I found was to replace it with a different route then replace it back to the previous route:

const to = router.currentRoute;
router.replace('/');
router.replace(to);

Which does what I want and re-run the route guards for the current page which handles the auth redirects without a full page reload.

How can i change RouterLink to "href"
@Phuongleduy
Am having the same issue here

How can i change RouterLink to "href"
@phuongleduy

router.beforeEach((to, from, next) => {
const requiresAuth = to.matched.some(record => record.meta.requiresAuth);
const currentUser = store.state.currentUser;

    if (requiresAuth && !currentUser) {
        next('/');

    } else if (to.path == '/' && currentUser) {
        next('/Dashboard');
    } else {
        next();
    }
});

axios.interceptors.response.use(null, (error)=>{
if(error.response.status === 401){
store.commit('logout');
router.push({path:'/'});
}
})

Agree with @mythz that is definitely should be supported via internal API: re-running route guards after logout w/o full page reloading.

I do this by resolving the route and then navigating the window using window.location.assign. This replaces the URL and causes the page to do a full request (refresh) rather than relying on Vue.router. $router.go does not work the same way for me, although it theoretically should.

    let r = this.$router.resolve({
        name: this.$route.name, // put your route information in
        params: this.$route.params, // put your route information in
        query: this.$route.query // put your route information in
      });
      window.location.assign(r.href)

This work perfect for me

this.$router.go({
          path: "/",
          force: true
        });

Using this.$router.go with anything other than an integer does not work if you are using typescript, FYI. I think technically it would still compile and run, but you'd get some nasty warning messages. Using this.$router.push('route', () => this.$router.go(0)) is the best I've found for now, but it does cause a full page reload so that may not be something you actually want.

@leggettc18 this worked for me, thanks!

Looks like this was pretty much patched up with 2.2 and Navigation Guards. These navigation guards are basically new lifecycle hooks.

For my case, I need to use:

beforeRouteEnter (to, from, next) {
  if (from.name === 'page1') {
     next(vm => {
        // access to component instance via `vm`; `this` is not recgonized otherwise;
        // `loadData` has my api and vuex components to update
        vm.loadData()
      })
   }
},

But most people in this thread appear to need to use beforeRouteUpdate.

Yes, Isee

Was this page helpful?
0 / 5 - 0 ratings