MithrilJS / mithril.js

A JavaScript Framework for Building Brilliant Applications
https://mithril.js.org
MIT License
14.02k stars 925 forks source link

[rewrite] Support use of history API state object in router #1480

Closed tobyzerner closed 7 years ago

tobyzerner commented 7 years ago

Mithril's router doesn't currently support use of a state object when routing. This is a problem for single page applications that want to implement correct browser back button behaviour.

For example, if I have two routes: A and B. The default route is A. I enter the site and do something to change the state of route A. Then I click a link through to route B. Now one of two things can happen:

Workarounds

One workaround is as follows: whenever state changes on route A, cache it on a global object. Then whenever route A is initialized, check the global for cached state and import it if it's present. Finally, when clicking the "home" link in route B, explicitly clear the cached state before routing back to A.

However, importantly, this does not actually produce identical behaviour to what using the history API properly would: if you start on route A, change state (which is cached), click a link to route B, click the "home" link to go back to route A, then clicked the browser back button twice (route A -> route B -> route A), the original cached state on route A will be lost.

Another workaround would be to serialize state in the URL... but this is far from elegant.

Possible solution

What if we allow another option to be passed in the m.route.set API. Whenever the state changes on route A, it can call the following:

m.route.set(path, data, {replace: true, attrs: {foo: 'bar'}})

This would set the given attrs object as the state when calling window.replaceState.

Then, when the back button is clicked, Mithril's window.onpopstate listener receives those attrs and can pass them into the component that is resolved from the new route (merged with the URL params). The component can then import the attrs into its state as appropriate.

I think this is important

The state object makes up a pretty important part of the history API and Mithril currently just ignores it completely. And I'd say I've put forth a pretty valid, common use-case — or at least one that should be common, if people are being responsible UX designers. Breaking the browser's back button and not providing a means for applications to fix it is pretty concerning.

lhorie commented 7 years ago

Added the state and title options to reflect the history.pushState API options.

See docs. See also this

tobyzerner commented 7 years ago

Beautiful, thank you @lhorie!