How to solve Avoided redundant navigation to current location error in vue?

I am new in vue and i got the error after user logged in and redirect to another route. Basically i am a PHP developer and i use laravel with vue. Please help me to solve this error.

Uncaught (in promise) Error: Avoided redundant navigation to current location: "/admin".

Here is the screenshot too

enter image description here

Vue Code

 methods: {
        loginUser() {
            var data = {
                email: this.userData.email,
                password: this.userData.password
            };
            this.app.req.post("api/auth/authenticate", data).then(res => {
                const token = res.data.token;
                sessionStorage.setItem("chatbot_token", token);
                this.$router.push("/admin");
            });
        }
    }

Vue Routes

const routes = [
    {
        path: "/admin",
        component: Navbar,
        name: "navbar",
        meta: {
            authGuard: true
        },
        children: [
            {
                path: "",
                component: Dashboard,
                name: "dashboard"
            },
            {
                path: "users",
                component: Users,
                name: "user"
            }
        ]
    },
    {
        path: "/login",
        component: Login,
        name: "login"
    }
];

const router = new VueRouter({
    routes,
    mode: "history"
});

router.beforeEach((to, from, next) => {
    const loggedInUserDetail = !!sessionStorage.getItem("chatbot_token");
    if (to.matched.some(m => m.meta.authGuard) && !loggedInUserDetail)
        next({ name: "login" });
    else next();
});


Solution 1:

As I remember well, you can use catch clause after this.$router.push. Then it will look like:

this.$router.push("/admin").catch(()=>{});

This allows you to only avoid the error displaying, because browser thinks the exception was handled.

Solution 2:

I don't think suppressing all errors from router is good practice, I made just picks of certain errors, like this:

router.push(route).catch(err => {
    // Ignore the vuex err regarding  navigating to the page they are already on.
    if (
      err.name !== 'NavigationDuplicated' &&
      !err.message.includes('Avoided redundant navigation to current location')
    ) {
      // But print any other errors to the console
      logError(err);
    }
  });

Solution 3:

Maybe this is happening because your are trying to route to the existing $route.matched.path.

For original-poster

You may want to prevent the error by preventing a route to the same path:

if (this.$route.path != '/admin') {
    this.$router.push("/admin");
}

Generic solutions

You could create a method to check for this if you are sending dynamic routes, using one of several options

  1. Easy: Ignore the error
  2. Hard: Compare the $route.matched against the desired route

1. Ignore the error

You can catch the NavigationDuplicated exception and ignore it.

pushRouteTo(route) {
    try {
        this.$router.push(route);
    } catch (error) {
       if (!(error instanceof NavigationDuplicated)) {
           throw error;
       }
    }
}

Although this is much simpler, it bothers me because it generates an exception.

2. Compare the $route.matched against the desired route

You can compare the $route.matched against the desired route

pushRouteTo(route) {
    // if sending path:
    if (typeof(route) == "string") {
        if (this.$route.path != route) {
            this.$router.push(route);
        }
    } else { // if sending a {name: '', ...}
        if (this.$route.name == route.name) {
            if ('params' in route) {
                let routesMatched = true;
                for (key in this.$route.params) {
                    const value = this.$route.params[key];
                    if (value == null || value == undefined) {
                        if (key in route.params) {
                            if (route.params[key] != undefined && route.params[key] != null) {
                                routesMatched = false;
                                break;
                            }
                        }
                    } else {
                        if (key in route.params) {
                            if (routes.params[key] != value) {
                                routesMatched = false;
                                break
                            }
                        } else {
                            routesMatched = false;
                            break

                        }
                    }
                    if (!routesMatched) {
                        this.$router.push(route);
                    }
                }
            } else {
                if (Object.keys(this.$route.params).length != 0) {
                    this.$router.push(route);
                }
            }
        }
    }
}

This is obviously a lot longer but doesn't throw an error. Choose your poison.

Runnable demo

You can try both implementations in this demo:

const App = {
  methods: {
    goToPageCatchException(route) {
      try {
        this.$router.push(route)
      } catch (error) {
        if (!(error instanceof NavigationDuplicated)) {
          throw error;
        }
      }
    },
    goToPageMatch(route) {
    if (typeof(route) == "string") {
        if (this.$route.path != route) {
            this.$router.push(route);
        }
    } else { // if sending a {name: '', ...}
        if (this.$route.name == route.name) {
            if ('params' in route) {
                let routesMatched = true;
                for (key in this.$route.params) {
                    const value = this.$route.params[key];
                    if (value == null || value == undefined) {
                        if (key in route.params) {
                            if (route.params[key] != undefined && route.params[key] != null) {
                                routesMatched = false;
                                break;
                            }
                        }
                    } else {
                        if (key in route.params) {
                            if (routes.params[key] != value) {
                                routesMatched = false;
                                break
                            }
                        } else {
                            routesMatched = false;
                            break

                        }
                    }
                    if (!routesMatched) {
                        this.$router.push(route);
                    }
                }
            } else {
                if (Object.keys(this.$route.params).length != 0) {
                    this.$router.push(route);
                }
            }
        } else {
          this.$router.push(route);
        }
    }
    },
  },
  template: `
  <div>
    <nav class="navbar bg-light">
          <a href="#" @click.prevent="goToPageCatchException({name:'page1'})">Catch Exception</a>
          <a href="#" @click.prevent="goToPageMatch({name:'page2'})">Match Route</a>
    </nav>
    <router-view></router-view>
  </div>`
}
const Page1 = {template: `
  <div class="container">
    <h1>Catch Exception</h1>
    <p>We used a try/catch to get here</p>
  </div>`
}
const Page2 = {template: `
  <div class="container">
    <h1>Match Route</h1>
    <p>We used a route match to get here</p>
  </div>`
}

const routes = [
  { name: 'page1', path: '/', component: Page1 },
  { name: 'page2', path: '/page2', component: Page2 },
]

const router = new VueRouter({
  routes
})

new Vue({
  router,
  render: h => h(App)
}).$mount('#app')
<link href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css" rel="stylesheet"/>
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/2.6.12/vue.min.js"></script>
<script src="https://unpkg.com/vue-router/dist/vue-router.js"></script>

<div id="app"></div>