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 history state access and modification #593

Closed
donnysim opened this issue Nov 14, 2020 · 2 comments
Closed

Allow history state access and modification #593

donnysim opened this issue Nov 14, 2020 · 2 comments

Comments

@donnysim
Copy link

What problem does this feature solve?

At first I came across this issue when I tried saving and restoring the scroll position of a container other than body which I did find a workaround for the time being but it ended up being tied to the browser instead of chosen history implementation of the router:

router.beforeEach(async (toRoute, from, next) => {
  if (window.history.state.current === from.fullPath) {
    const pageScroll = document.querySelector('.page-container');

    if (pageScroll) {
      window.history.state.pageScroll = {
        top: pageScroll.scrollTop,
      };
    }
  }

  next();
});

router.afterEach(() => {
  window.requestAnimationFrame(() => {
    const pageScroll = document.querySelector('.page-container');

    if (pageScroll) {
      if (window.history.state.pageScroll) {
        pageScroll.scrollTop = window.history.state.pageScroll.top;
      } else {
        pageScroll.scrollTop = 0;
      }
    }
  });
});

It would be great if we could access and modify active history state in before and after hooks. Main reason is that it would allow storing a cache data or id for pages where we could resolve the data from the state - primarily for better handling of the back button where we could just restore data from old state instead of fetching it again. This could possibly simplify form data saving and restoration and in addition this would also allow many more possibilities to solve problems where the router (currently) cannot like storing custom scroll positions and restoration of one or more scroll containers.

What does the proposed API look like?

Maybe introduce a state object inside the route where it allows modifying the state directly:

router.beforeEach(async (toRoute, fromRoute, next) => {
  if (!toRoute.state.cacheData) {
    toRoute.state.cacheData = await toRoute.meta.fetch();
  }

  // should it be cloned to avoid outside modification?
  // also can be avoided if we can just access the state in `props` resolve function
  toRoute.meta.resolved = toRoute.state.cacheData;

  next();
});

And maybe also allow access and modification directly from the current route:

router.currentRoute.value.state.cacheData = { ... }

Another possibility would be to introduce a unique id for each route history entry that can be accessed and we could store additional data based on it, though it would require additional effort to implement storage and clearing for stale state. We cannot use position key because they can clash across multiple tabs.

I think having a unique ID - UUIDv4 etc. might be beneficial in any case.

@posva
Copy link
Member

posva commented Nov 16, 2020

History state being platform-specific and use-case specific, it's better to handle it in userland. The router allows you to attach data to to.meta in any navigation guard.

When it comes to the Web History API, there is a still internal property data that can be passed to router.push({ path: '/foo', data: {} }), it still needs to go through an RFC (vuejs/vue-router#2243) thought so use at your own risk since the name could change or disappear in the future. For an example on how to write to the history state, check the modal e2e test 😉

@posva posva closed this as completed Nov 16, 2020
@donnysim
Copy link
Author

Oh nice, thanks, didn't notice the rfc before.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants