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

Keep history.state in sync with $page.state #13293

Open
rChaoz opened this issue Jan 8, 2025 · 0 comments
Open

Keep history.state in sync with $page.state #13293

rChaoz opened this issue Jan 8, 2025 · 0 comments

Comments

@rChaoz
Copy link
Contributor

rChaoz commented Jan 8, 2025

Describe the problem

In the current version, the state read using $page.state (or the newer $app/state version) can easily get out of sync with the actual history.state, two very common methods are:

This can have certain consequences depending on how you use shallow state. I use it for drawers/modals, and this un-sync thing causes many issues, such as the back button not working after a refresh (history.state is popped but nothing happens as $page.state is already empty). Then, clicking the forward button makes the popup magically appear, as SvelteKit finally uses the browser state.

This feels like a bug, which is why so many issues have been opened on this topic, at least 3-4 other than the 2 mentioned above, such as #13139, which actually prompted me to write this issue to group everything together.

Describe the proposed solution

I understand the initial thoughts behind the choice to make the state reset on refresh - to avoid flashes during hydration. However, improving SSR at the cost of breaking CSR is not the correct choice IMO.

The primary use-cases of shallow routing are:

  1. With URL change - this allows for example, as Rich Harris stated, to implement preview navigation. The user clicks on an image, and a dialog/similar viewer appears in the current page, and /image/12345 is appended to the URL using shallow routing. Upon refreshing the page, the new URL is requested from the server, which opens up a new full page viewer. This is also the page that is opened, for example, when sharing the URL or arriving from a search engine.
  2. Without URL change - this cannot be used with SSR as the local state is never available on the server, unlike the URL change. This can be used, for example, to control dialogs and drawers, this avoid the very common annoyance when you try to use the back button on a mobile browser, and instead of closing the current modal, the page is exited altogether.

The question is: to delete or not delete the state on page refresh? For case 1, it should be deleted, as an entire new page is loaded, which does not use this state. For case 2, it depends - do we want the dialog/drawer to re-open after a refresh? Sometimes the answer is yes, but this depends on the app.

Currently, the state is always deleted, although in this buggy manner where it's actually still there causing the back button to not work, or causing it to reappear after going back/forward. There are a few changes that can be done:

  • correctly delete the state from history.state, however this is very tricky or even impossible to do. This would fix the issues associated with use-case 2 described above.
  • allow the user to decide if the state should be restored in hydration (feature/minor change)
  • change the default behaviour depending on whether the URL is changed, or if SSR is disabled for the page (breaking change for v3)

Finally, there's the issue of page state being deleted on form submissions, but I believe this is the exact same issue as above. Consider a form without use:enhance. If the state is deleted on page refresh, this is identical to the state being deleted on submission in an enhanced form. This is why the behaviour of form submissions should be the same as for a page refresh by default, but still configurable, as it's not a full-page reload after all.

Workaround

You can find a workaround that keeps the page state in sync by loading it from history.state on page load here.

Importance

would make my life easier

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

1 participant