Some non-navigating setState() is probably needed #115
Labels
feedback wanted
foundational
Foundational open questions whose resolution may change the model dramatically
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 doappHistory.navigate(url, { state: newState })
and then intercept this using thenavigate
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 disconnectedhistory.pushState()
call, you initiate a navigation usingappHistory.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 thathistory.state
is fragile and terrible): you listen fortoggle
events and then dohistory.replaceState()
to synchistory.state
with the<details>
.With app history it's more awkward. You could listen for the
toggle
event and then doappHistory.navigate({ state: newState })
(orappHistory.reload({ state: newState })
per #112). But then you need to have yournavigate
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...)The text was updated successfully, but these errors were encountered: