router
router copied to clipboard
Allow accessing history state from Route-objects
While I was refactoring my code to remove artificial params in lieu of the 4.1.4 release to write my data to the history.state
object, I noticed that I can pass a state
property to $router.push()
and was kind of surprised that I could not retrieve it with $route.state
(like I can with queries or params) but had to access it using window.history.state
.
Would it be possible to implement a state
property containing only the passed state in the RouteLocationNormalizedLoaded
interface?
That would make it a more intuitive replacement for the removed artificial params IMO.
history.state
has a few limitations and I'm still not sure it can be included in all locations. For example, it cannot be included in to
locations in navigation guards, so, unfortunately, it cannot be added to any existing RouteLocation...
. This would need yet another route location type variant.
Note that right now this can be achieved with a guard:
router.afterEach(to => {
to.state = history.state
})
but there are other alternatives like a composable useHistoryState()
:
import { shallowRef, onScopeDispose } from 'vue'
function useHistoryState<T = unknown>(router?: Router) {
const state = shallowRef<T>(history.state)
const remove = (router || useRouter()).afterEach(() => {
state.value = history.state
})
onScopeDispose(remove)
return state
}
This variant is in a pending PR at #2106
I think ultimately, we want to go with another route location variant but it would be helpful to explore other possibilities and possible caveats.
Hey! I found this issue looking for an alternative solution for sending arbitrary params (or artificial params @amxmln) when using router.push
since this is not supported anymore with regular route params. Since you can pass state
as an option in the router.push
I thought that could be the perfect candidate but I'm hitting issues as well when trying to retrieve the state I'm sending.
My use-case is that I want to have different scroll behaviour depending on where the navigation push was initiated (we don't want to scroll at the top when switching tabs)
{
scrollBehavior (to) {
// It would be great to be able to retrieve history state or more generally artificial params here
},
}
Bottom line, what I'm trying to say is that it seems there is plenty of use-case for artificial params (aka navigation-based arbitrary data) and I understand history state is probably not the right fit. But with the new version preventing arbitrary params what are the alternatives ?
@AlexandreBonaventure alternatives are in the changelog
Yes, I appreciate you are providing migration steps, but going back to my specific use-case I don't see any alternatives working for me:
- Putting the data in a store: does not feel right because that's really not a global state
- Move the data to an actual param: not relevant either because that's not a URL-based state
- Pass the data as state to save it to the History API state: as per this conversation is not fitting the use-case
-
Pass it as a new property to
to.meta
during navigation guards: does not seem to work for me because I can't set the meta when pushing the navigation like that for instancerouter.push({ name: 'test', meta: { test: 'heyyy' } });
Let me know if I missed something or if I'm off-topic.
I know this is a github issue and not a support forum, but I wonder if the above scenario is warranting another API for dealing with so-called artificial params, which could benefit to other users as well.
--- Alternatives (things that could work for me)
- allow to send meta with router.push/replace/etc (I like the simplicity of this one, but I have to say being a user for a long time of vue-router, that modifying meta object feels like an undocumented/hidden feature, since to me meta object is declarative)
- provide a brand new option in RouteLocationOptions
- or ??
There won’t be a new api for artificial params (aka state) as it was removed before for being a bad practice (for the reasons mentioned in the changelog and others I probably forgot since it’s been more than 5 years 😅)
Your use case does sound like it should use a store. Stores are not only for global state or you could also say that if state lives through different pages, it is global. Or maybe https://github.com/vuejs/rfcs/discussions/460 👀
@AlexandreBonaventure what about using query
instead of params