添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
Collectives™ on Stack Overflow

Find centralized, trusted content and collaborate around the technologies you use most.

Learn more about Collectives

Teams

Q&A for work

Connect and share knowledge within a single location that is structured and easy to search.

Learn more about Teams

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

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();

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.

This can be extended to if (this.$route.name !== 'navbar') this.$router.push("/admin").catch(()=>{}); – IVO GELOV Jun 19, 2020 at 7:07 If this was the only possible meaningful error that could arise from calling push() then sure... but that's not the case so you'll suppress every error message coming from there. This shouldn't be the accepted answer. – nucleogenesis Oct 14, 2020 at 21:10

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.
      err.name !== 'NavigationDuplicated' &&
      !err.message.includes('Avoided redundant navigation to current location')
      // But print any other errors to the console
      logError(err);

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

  • Easy: Ignore the error
  • 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: `
        <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>
        <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/bootstrap@4.5.3/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>
    You can compare the full path with the router resolver used as this.$router.resolve(params).route.fullPath. That will give you full path with query params back where you then compare with === against the current this.$route.fullPath. – Gkiokan Dec 24, 2020 at 9:02

    Just to make this complete you can also compare the from and to route fullPaths and compare them against each other which seems to me a simple, valid and reusable solution.

    Here is an example in a component method:

     move(params){
        // get comparable fullPaths
        let from  = this.$route.fullPath
        let to    = this.$router.resolve(params).route.fullPath
        if(from === to) { 
            // handle any error due the redundant navigation here
            // or handle any other param modification and route afterwards
            return 
        // route as expected
        this.$router.push(params)
    

    If you wanna use that you just put your route params in it like this.move({ name: 'something' }). This is the easiest way to handle the duplicate route without running into try catch syntax. And also you can have that method exported in Vue.prorotype.$move = ... which will work across the whole application.

    I found the solution by adding the following code to router.js:

    import router from 'vue-router'; 
    const originalPush = router.prototype.push
    router.prototype.push = function push(location) {
      return originalPush.call(this, location).catch(err => err)
    

    Provide a Typescript solution

    The idea is to overwrite the router.push function. You can handle (ignore) the error in one place, instead of writing catch everywhere to handle it.

    This is the function to overwrite

    export declare class VueRouter {
      // ...
      push(
        location: RawLocation,
        onComplete?: Function,
        onAbort?: ErrorHandler
      ): void
    

    Here is the code

    // in router/index.ts
    import Vue from 'vue';
    import VueRouter, { RawLocation, Route } from 'vue-router';
    Vue.use(VueRouter);
    const originalPush = VueRouter.prototype.push;
    VueRouter.prototype.push = function push(location: RawLocation): Promise<Route> {
      return new Promise((resolve, reject) => {
        originalPush.call(this, location, () => {
          // on complete
          resolve(this.currentRoute);
        }, (error) => {
          // on abort
          // only ignore NavigationDuplicated error
          if (error.name === 'NavigationDuplicated') {
            resolve(this.currentRoute);
          } else {
            reject(error);
    // your router configs ...
                    Thank you for this! Vue is all the better for having people able to provide Typescript examples!
    – James Hyde
                    Apr 20, 2021 at 14:35
                    Excellent solution, though the check for whether to ignore the error should probably be error.name === 'NavigationDuplicated' || error.message.includes('Avoided redundant navigation to current location')  . Checking for the error name wasn't working for me.
    – stellr42
                    Sep 9, 2021 at 13:34
    

    you can define and use a function like this:

    routerPush(path) {
      if (this.$route.path !== path) {
        this.$router.push(path);
                    Why is this not built-in?? Should be default behavior and then there could be force push option.
    – mspoulsen
                    Mar 5, 2021 at 12:44
    

    It means - you want to navigate to a route that looks the same as the current one and Vue doesn’t want to trigger everything again.

     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);
                // Here you conditioally navigate to admin page to prevent error raised
                if(this.$route.name !== "/admin") {
                  this.$router.push("/admin");
    

    Clean solution ;)

    Move the code to an util function. So you can replace all this.$router.push with it.

    import router from '../router'; // path to the file where you defined 
                                    // your router
    const goToRoute = (path) => 
        if(router.currentRoute.fullPath !== path) router.push(path);
    export {
        goToRoute
    

    In addition to the above mentioned solutions: a convenient way is to put this snippet in main.js to make it a global function

    Vue.mixin({ * Avoids redundand error when navigating to already active page routerPush(route) { this.$router.push(route).catch((error) => { if(error.name != "NavigationDuplicated") { throw error;

    Now you can call in any component:

    this.routerPush('/myRoute') 
    const onError = (e) => {
      // avoid NavigationDuplicated
      if (e.name !== 'NavigationDuplicated') throw e
    // keep original function
    const _push = router.__proto__.push
    // then override it
    router.__proto__.push = function push (...args) {
      try {
        const op = _push.call(this, ...args)
        if (op instanceof Promise) op.catch(onError)
        return op
      } catch (e) {   
        onError(e)
    

    I have added the code below in the main.js file of my project and the error disappeared.

    import Router from 'vue-router'
    const routerPush = Router.prototype.push
    Router.prototype.push = function push(location) {
    return routerPush.call(this, location).catch(error => error)
    

    I have experienced the same issue and when I looked for a solution I found .catch(() => {}) which is actually telling the browser that we have handled the error please don’t print the error in dev tools :) Hehehe Nice hack! but ignoring an error is not a solution I think. So what I did, I created a utility function that takes two parameters router, path, and compares it with the current route's path if both are the same it means we already on that route and it ignore the route change. So simple :)

    Here is the code.

    export function checkCurrentRouteAndRedirect(router, path) {
      const {
        currentRoute: { path: curPath }
      } = router;
      if (curPath !== path) router.push({ path });
    checkCurrentRouteAndRedirect(this.$router, "/dashboard-1");
    checkCurrentRouteAndRedirect(this.$router, "/dashboard-2");
    

    I had this problem and i solve it like that.

    by adding that in my router file

    import Router from 'vue-router'

    Vue.use(Router)

    const originalPush = Router.prototype.push 
    Router.prototype.push = function push(location) {
       return originalPush.call(this, location).catch(err => err)
    
      if (this.$router.currentRoute.name !== 'routeName1') {
        this.$router.push({
          name: 'routeName2',
    

    Late to the party, but trying to add my 10 cents. Most of the answers- including the one which is accepted are trying to hide the exception without finding the root cause which causes the error. I did have the same issue in our project and had a feeling it's something to do with Vue/ Vue router. In the end I managed to prove myself wrong and it was due to a code segment we had in App.vue to replace the route in addition to the similar logic like you in the index.ts.

    this.$router.replace({ name: 'Login' })
    

    So try to do a search and find if you are having any code which calls $router.replace OR $router.push for the route you are worried about- "/admin". Simply your code must be calling the route more than once, not the Vue magically trying to call it more than once.

    I guess this answer comes in super late. Instead of catching the error I looked for a way to prevent the error the come up. Therefore I've enhanced the router by an additional function called pushSave. Probably this can be done via navGuards as well

    VueRouter.prototype.pushSave = function(routeObject) {
      let isSameRoute = true
      if (this.currentRoute.name === routeObject.name && routeObject.params) {
        for (const key in routeObject.params) {
            !this.currentRoute.params[key] ||
            this.currentRoute.params[key] !== routeObject.params[key]
            isSameRoute = false
      } else {
        isSameRoute = false
      if (!isSameRoute) {
        this.push(routeObject)
    const router = new VueRouter({
      routes
    

    As you've probably realized this will only work if you provide a routeObject like

    this.$router.pushSave({ name: 'MyRoute', params: { id: 1 } })
    

    So you might need to enhance it to work for strings aswell

    Component name: <to-link>

    <template>
      <router-link :to="to" :event="to === $route.path || loading ? '' : 'click'" :class="classNames">
        <slot></slot>
      </router-link>
    </template>
    <script>
    export default {
      name: 'ToLink',
      props: {
        to: {
          type: [String, Number],
          default: ''
        classNames: {
          type: String,
          default: ''
        loading: {
          type: Boolean,
          default: false
    </script>
    

    For bind:

    import ToLink from '@/components/to-link'
    Vue.component('to-link', ToLink)
    
  • For $router.push() need create global method.
  • toHttpParams(obj) {
        let str = ''
        for (const key in obj) {
          if (str !== '') {
            str += '&'
          str += key + '=' + encodeURIComponent(obj[key])
        return str
      async routerPush(path, queryParams = undefined, params = undefined, locale = true) {
        let fullPath = this.$route.fullPath
        if (!path) {
          path = this.$route.path
        if (!params) {
          params = this.$route.params
        if (queryParams && typeof queryParams === 'object' && Object.entries(queryParams).length) {
          path = path + '?' + this.toHttpParams(queryParams)
        if (path !== fullPath) {
          const route = { path, params, query: queryParams }
          await this.$router.push(route)
    

    I don't understand why they no longer handle this case internally, but this is what I have implemented in our app.

    If you are already on the fullPath then dont bother pushing / replacing

    const origPush = Router.prototype.push;
    Router.prototype.push = function(to) {
      const match = this.matcher.match(to);
      // console.log(match.fullPath, match)
      if (match.fullPath !== this.currentRoute.fullPath) {
        origPush.call(this, to);
      } else {
        // console.log('Already at route', match.fullPath);
    const origReplace = Router.prototype.replace;
    Router.prototype.replace = function(to) {
      const match = this.matcher.match(to);
      // console.log(match.fullPath, match)
      if (match.fullPath !== this.currentRoute.fullPath) {
        origReplace.call(this, to);
      } else {
        // console.log('Already at route', match.fullPath);
                    This is a very hacky solution.  I would strongly discourage passing unnecessary data to avoid fixing the bug.
    – Jamie Marshall
                    Feb 25, 2022 at 21:17
            

    Thanks for contributing an answer to Stack Overflow!

    • Please be sure to answer the question. Provide details and share your research!

    But avoid

    • Asking for help, clarification, or responding to other answers.
    • Making statements based on opinion; back them up with references or personal experience.

    To learn more, see our tips on writing great answers.