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

Some non-navigating setState() is probably needed #115

Closed
domenic opened this issue May 20, 2021 · 2 comments
Closed

Some non-navigating setState() is probably needed #115

domenic opened this issue May 20, 2021 · 2 comments
Labels
feedback wanted foundational Foundational open questions whose resolution may change the model dramatically

Comments

@domenic
Copy link
Collaborator

domenic commented May 20, 2021

The API currently only allows you to update the app history state via navigation. E.g., to get the equivalent of history.pushState(newState, "", url) you would do appHistory.navigate(url, { state: newState }) and then intercept this using the navigate event to convert it into a single-page app navigation. The thinking here is to flip the traditional model on its head: instead of updating the document and then syncing the URL + history stack + state with a disconnected history.pushState() call, you initiate a navigation using appHistory.navigate(), and in a centralized fashion do SPA processing. This explainer section shows some of the advantages.

However, there are some cases where this model doesn't seem to work very well. That's when you need to update the current state in response to an external event, often caused by user interaction.

Here is an example. Consider a page with expandable/collapsable <details> elements. You want to store the expanded/collapsed state of these <details> elements in your app history state, so that when the user traverses back and forward through history, or restarts their browser, your app can read the restored app history state and expand the <details> elements appropriately, showing the user what they saw previously.

To do this using history.replaceState() is relatively easy (modulo the fact that history.state is fragile and terrible): you listen for toggle events and then do history.replaceState() to sync history.state with the <details>.

With app history it's more awkward. You could listen for the toggle event and then do appHistory.navigate({ state: newState }) (or appHistory.reload({ state: newState }) per #112). But then you need to have your navigate handler do nothing, because the <details> element is already open. This is certainly doable, but it points out how the model we're forcing you into is a bit awkward.

To summarize, not every state update causes a page update; instead, sometimes a state update is to capture an externally-driven page update.

For cases like these, we might need something like appHistory.current.setState() (briefly introduced, but removed in #61.)

Points of discussion:

  • Is this a big problem worth solving? Or is it OK for cases like this to involve navigate handlers that purposefully do nothing?

  • Is this true for just state, or are there cases where it makes sense for URLs too? You could imagine a site that wanted to store UI state like <details> open-ness in the URL, but I'm not sure we should design the API around such cases.

  • If we add setState(), should it be able to set the state of any entry, or just the current one?

  • If we add setState(), how do we encourage people to avoid it in cases where the state update should drive a page update (for which our existing pattern works best), and instead only use it in cases where a page update drives a state update? Just documentation?

  • The above example shows page-driven state updates. Are there page-driven history entry addition cases, where something like history.pushState() would make sense? (I hope not...)

@domenic
Copy link
Collaborator Author

domenic commented May 20, 2021

I'll note that one of the README examples suffers from this currently: https://github.com/WICG/app-history/tree/e7f230fb569407bce2bbb53e86a5ed744bf658a9#per-entry-events says "When we navigate away from this photo, save any changes the user made." and does it via an appHistory.navigate({ replace: true, state: newState }) call.

@domenic
Copy link
Collaborator Author

domenic commented May 20, 2021

This was previously discussed in #57.

@domenic domenic added feedback wanted foundational Foundational open questions whose resolution may change the model dramatically labels May 27, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feedback wanted foundational Foundational open questions whose resolution may change the model dramatically
1 participant