Throw Error "NavigationDuplicated"
tcastelly opened this issue ยท 15 comments
Version
3.1.1
Reproduction link
https://codesandbox.io/s/vue-template-i2d63
Steps to reproduce
Use $router.push
to change the "page". If you are using the same page, vue-router throw an Error.
What is expected?
Just nothing, or a warning.
What is actually happening?
An Error has been thrown.
- To my point of view it's not an error. On a previous version of 'vue-router' no error was threw: https://codesandbox.io/s/vue-template-qvrfr
<router-link>
does not have the same behavior. There is no error even if you're pushing the current page.
This is expected, it's part of the new promise api: before, if no callbacks were supplied to router.push
, errors were only sent to the global router error handler. Now, because they return a promise, if the error is not caught, you will see a warning in the console. But the error was always there because trying to navigate to same location as the current one will fail
The behavior with router-link
is consistent with how it was working before, no errors are emitted (except globally), it's catching the error by adding a noop callback:
router.push('/location', () => {})
However, the correct solution if you don't care about errors is catching the error:
router.push('/location').catch(err => {})
The last version makes more sense as the Promise api is likely to become the default and the callback version to become deprecated
Hi @posva
In your types folder you can still find the push method as void
https://github.com/vuejs/vue-router/blob/dev/types/router.d.ts
is there a plan to fix this also ?
there are two versions of push and replace matching what actually happens
pushing a new URL (that is the same path as current page) but the search/hash makes the URL different, doesn't work anymore.
@shmaram I will give it a try and push a fix during the day, thanks for letting me know!
It's fixed now, I will publish a version during the day
@posva Why does it throw a NavigationDuplicated error when updating params, though? For instance, the router page might be named "User" and have params: { id: userId }
. If you call this.$router.push({ name: 'User', params: { id: selectedUserId }})
to change the user being rendered for the current page, should that really count as a NavigationDuplicated error? This is the way it is recommended to change the data for a page, so it seems odd that getting an error is expected behavior.
the navigation failure should only happen if the final location is the same as the current one. If it happens with different params, it's a bug so please open a new issue with a boiled down repro
@posva Why does it throw a NavigationDuplicated error when updating params, though? For instance, the router page might be named "User" and have
params: { id: userId }
. If you callthis.$router.push({ name: 'User', params: { id: selectedUserId }})
to change the user being rendered for the current page, should that really count as a NavigationDuplicated error? This is the way it is recommended to change the data for a page, so it seems odd that getting an error is expected behavior.
I can confirm this behavior using this.$router.replace()
. Just replacing the query params will cause the NavigationDuplicated
error.
E.g., replacing #/search?term=lorem&sort=relevance
with #/search?term=lorem&sort=alphabetical
via
this.$router.replace({
path: '/search',
query: {
term: 'lorem',
sort: 'alphabetical'
}
})
will cause the NavigationDuplicated
error if not catching via
this.$router.replace({
path: '/search',
query: {
term: 'lorem',
sort: 'alphabetical'
}
}).catch(err => {})
It will correctly update the current URL regardless of catching the error or not though.
Is this.$router.replace()
not intended to be used for this? I didn't see any other function in the docs for just replacing the query params.
Is there a shorter way the prevent the console warning than router.push('/location').catch(err => {})
?
Is it possible to decorate the push method to handle errors with a noop function?
@posva and what about redirecting inside a route guard?
next({ replace: true, name: 'home' }).catch(err => {})
Is this even possible? Because I'm getting this error caused by a route guard :(
@posva Why does it throw a NavigationDuplicated error when updating params, though? For instance, the router page might be named "User" and have
params: { id: userId }
. If you callthis.$router.push({ name: 'User', params: { id: selectedUserId }})
to change the user being rendered for the current page, should that really count as a NavigationDuplicated error? This is the way it is recommended to change the data for a page, so it seems odd that getting an error is expected behavior.I can confirm this behavior using
this.$router.replace()
. Just replacing the query params will cause theNavigationDuplicated
error.E.g., replacing
#/search?term=lorem&sort=relevance
with#/search?term=lorem&sort=alphabetical
viathis.$router.replace({ path: '/search', query: { term: 'lorem', sort: 'alphabetical' } })will cause the
NavigationDuplicated
error if not catching viathis.$router.replace({ path: '/search', query: { term: 'lorem', sort: 'alphabetical' } }).catch(err => {})It will correctly update the current URL regardless of catching the error or not though.
Is
this.$router.replace()
not intended to be used for this? I didn't see any other function in the docs for just replacing the query params.
Is this fixed?
AFAIK the problem didn't appear when I tried. As with any other bug, a boiled reproduction is required. So please open a new issue with it if you can reproduce it. One possibility for the error to happen is to have another push somewhere else or next
being called with the same location as the current one. I gave more details about it at #2881 (comment)
Locking this one to redirect to that issue