Allow changing history.state
with router.push()
#400
Replies: 5 comments 2 replies
-
This RFC is now in final comments stage. An RFC in final comments stage means that: The core team has reviewed the feedback and reached consensus about the general direction of the RFC and believe that this RFC is a worthwhile addition to the framework. |
Beta Was this translation helpful? Give feedback.
-
Wow such a great feature! Just a small feedback, I loved the import { useRouteState } from 'vue-router'
// get all state, returns Ref<unknown> / WritableComputedRef<unknown>
const state = useRouteState()
// get a specific state key with a default value, returns Ref<boolean> / WritableComputedRef<boolean>
const isFooModalOpen = useRouteState((state) => state.modals.foo.open, false) Note: changing those values can seamlessly call |
Beta Was this translation helpful? Give feedback.
-
How's this RFC coming along, Is it stable to use in production? |
Beta Was this translation helpful? Give feedback.
-
In 4.2.5 right now. Pushing the same route with a new state property does not trigger reentering into the route. |
Beta Was this translation helpful? Give feedback.
-
@posva Hey, sorry for pinging you, but any chances this feature will be added? Or maybe there is any workaround how to do it now? I just have the situation where I need to changle the url of page without triggering of rerender, and I do it via history but vue router doesn't know anything about that( |
Beta Was this translation helpful? Give feedback.
-
Summary
state
property alongsidepath
,query
, and other properties to persist tohistory.state
.history.state
directly atthis.$route.state
.Basic example
Programmatic navigation:
Declarative:
Motivation
Passing state through the
history
API is a native feature that is currently hard to use when using Vue Router. While it has its limitations, it has many useful usecases like showing modals and can be use as a source of truth for state that is specific to certain locations and should be persisted across navigations when coming back to a previously visited page.Currently, this can be achieved most of the times with
It currently cannot be achieved if the current location is the same and the only thing we want to do is modify the state.
The router should facilitate using the features of the History API but currently it turns out to make the task of writing to
history.state
difficult or impossible (e.g. same location navigation)Detailed design
Writing to
history.state
Vue Router 4 already uses
history.state
internally to detect navigation direction and revert UI initiated navigations such as the back and forward button. In order to not interfere with the information stored by it, it should save the state passed by the user to a nested property:Duplicated navigations
By default, the router avoids any duplicated navigation (e.g. clicking multiple times on the same link) or calling
router.push('/somewhere')
when we are already at/somewhere
. Whenstate
is passed torouter.push()
(orrouter.replace()
), the router should always create a new navigation. This creates a hidden way to force a navigation to the same location and also the possibility to have multiple entries on the history stack that point to the same URL but this should be fine as they should contain different state./search
router.push({ state: { searchResults: [] }})
/search
but the page can use the passed state to display a different version/search
but see a different version of the pageInvalid state properties
Since the state must be serializable, some key or property values are invalid and should be avoided (e.g. DOM nodes or complex objects, functions, Symbols). Vue Router won't touch the state given by the user and pass it as is to
history.pushState()
. The developer is responsible for this and must be aware that browsers might treat some Data Structures differently.SSR
Since this feature only works with the History API, any given
state
property passed torouter.push()
will be ignored during SSR by the Memory History implementation.Reading the state
It would be convenient to be able to read the
history.state
directly from the current route because that would make it reactive and allow watching or creating computed properties based on it:For convenience reasons, the
route.state
property should be an empty object by default.This introduces a new TS interface to represent the current location as the History API only allows reading from the current entry. Therefore
from.state
is unavailable in Navigation guards whileto.state
can be available:Drawbacks
route.state
retrieve onlyhistory.state.userState
allows us to not expose the information stored by the router (since it's not public API) but also doesn't allow information stored in thehistory.state
by other libraries. I think this is okay because the user can create a computed property to read from those properties withcomputed(() => route && history.state.myOwnProperty)
.Alternatives
route.state
property could beundefined
when not set.route.state
be the wholehistory.state
instead of what the user passedAdoption strategy
Currently Vue Router 4 allows passing a
state
property torouter.push()
but the API is not documented and marked as@internal
and should therefore not be used. Other than that, this API is an addition.Unresolved questions
Beta Was this translation helpful? Give feedback.
All reactions