Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow accessing history state from Route-objects #1535

Open
amxmln opened this issue Aug 26, 2022 · 6 comments
Open

Allow accessing history state from Route-objects #1535

amxmln opened this issue Aug 26, 2022 · 6 comments
Labels
discussion This problem still needs more feedback enhancement New feature or request

Comments

@amxmln
Copy link

amxmln commented Aug 26, 2022

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.

@posva
Copy link
Member

posva commented Aug 26, 2022

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.

@posva posva added enhancement New feature or request discussion This problem still needs more feedback labels Aug 26, 2022
@AlexandreBonaventure
Copy link

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 ?

@posva
Copy link
Member

posva commented Aug 31, 2022

@AlexandreBonaventure alternatives are in the changelog

@AlexandreBonaventure
Copy link

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 instance router.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 ??

@posva
Copy link
Member

posva commented Aug 31, 2022

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 vuejs/rfcs#460 👀

@mirko77
Copy link

mirko77 commented Jun 15, 2023

@AlexandreBonaventure what about using query instead of params

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
discussion This problem still needs more feedback enhancement New feature or request
Projects
None yet
Development

No branches or pull requests

4 participants