hyperapp-router
hyperapp-router copied to clipboard
State-first routing
The current routing approach lets you control which components render based on the curent window.location, but it does not take into account the need for other side effects when the route changes. (Typically: fetching some data based on a route-parameter)
I propose we instead start thinking of route-changes as events, and take the same approach as we do for other events: call an action when the route changes (passing the match-data as argument). Then it is up to the actions set the state and perform side-effects accordingly.
The main benefit is that it allows you to trigger side effects (like data fetch) on route changes. It also (IMO) makes the view, and its relationship to the state more straightforward and easier to reason about, since we don't need to sprinkle in <Route .../> components. ... It just makes sense :)
Here's an example using this approach to routing:
https://codepen.io/zaceno/pen/KQbpVG?editors=0010
...That API is perhaps a bit rough to be a proper proposal, but it illustrates the idea. I think it should probably look more like this:
import router from 'router'
const main = app(
//STATE
{
router: router.state,
page: 'home',
foo: null,
...
},
//ACTIONS
{
router: router.actions,
setFoo: id => {
//...side effect here //
return ({page: 'foo', foo: id})
},
setHomePage: _ => ({page: 'home', foo: null}),
...
},
//VIEW
(state, actions) => (
<main>{
state.page === 'home' ? <HomePage />
: state.page === 'foo' ? <FooPage foo={state.foo} />
}</main>
),
//CONTAINER
document.body
)
//INITIALIZATION
router.subscribe(main.router, [
{route: '/foo/:id', action: ({id}) => main.setFoo(id)},
{route: '/', action: main.setHomePage]
])
@lukejacksonn
What are your feelings about this? Had to ask since https://github.com/lukejacksonn/hyperapp-fetch will break with the next hyperapp update
I am still on the side of declarative routing and data fetching. Routing is really hard. There are so many ways to go about it, so many edge-casey requirements that I believe flexibility is the number one priority and that is what keeping things in the view gets you. This is just my personal experience.
There have not been many complaints about the approach taken here, I'm not suggesting it is the perfect implementation but it is a shame to have to throw this option away and completely shift arch because of the next release.
I'd love to see a router in the arch you describe with feature parity of the current offering (like nested routes etc.). I haven't really thought about it yet, so by all means don't let me stop you 👍I always saw the router as a way of demonstrating interop of plugin type functionality anyway, it would be great to see what you come up with!
EDIT: Did not meant to write an essay there 😅 here is the router aside edit
On that topic, it is interesting to see even more things being pushed to the view as declarative now (like data fetching and dynamic imports) in react, and we are about to make it impossible entirely. I guess we are going to have to use
oncreatefor more things now (like hyperapp-fetch; it is still weird to me that the view is always going to be one state render behind if you call an action from a view); that said, subviews look useful, it is a shame we couldn't have both.
If I am not mistaken, the only part that will change due to the new architecture is the Redirect component.
Hello. I'm a new Hyperapp user, but not a Hyperapp router user. I'm not a fan of expressing opinions without trying stuff but TBH the moment I saw the Route component I decided not to go further with it.
IMHO the future of routing is the state first approach. It has so many benefits some of which are expressed by @zaceno above.
I kind of find it funny to see routing reinvented with each new framework, when it could easily be decoupled from it. I personally make use of the Router5 package for my routing needs. The benefits of state first and framework agnostic routing can be read from their website as well. It is also a reasonably advanced routing solution that has support for nesting routes, middleware, etc.
I'm not sure if a state first router for Hyperapp needs to be invented from scratch. I'm planning to develop a Hyperapp wrapper for Router5 in the coming days which can in fact fulfill that need. And this router can continue to serve the developers that have traditional routing mindsets, as an important part of the ecosystem.
Please correct me if I'm missing anything.
Hyperapp is great work and I'm happy to see the ecosystem growing.
Now that the router is Lazy Components first, and Lazy Components will be teared down with the 2.0 release. We will need to work on a new one strongly related to the new 2.0 API and concept. See hyperapp/hyperapp#672
The 2.0 will be more about action as FX, and state-first things. So I bet the router will follow this line too.
If you have any intel about how the router can be aligned with the new 2.0 proposal feel free to enlighten us.
But TBH looking at the Router5 API, it is pretty close to what I have in mind for this. See the RiotJS router too.
I just pushed the initial version of a Hyperapp-Router5 adapter: https://github.com/gwn/hyperapp-router5-adapter. I'd be happy to hear any feedback. I'd like to publish it in NPM with the name @hyperapp/router5-adapter if the community approves of it.
@Swizz thank you for your comment. I'm actually excited about Hyperapp 2.0. As I'm advocating the use of a separate and established router package such as Router5 for routing needs; I actually don't have any proposals regarding the new version of the router.
I should note that I made the adapter support FX as well by providing a navigate effect. (Which of course only makes sense when Hyperapp FX is in use.) And I'm sure that this adapter can be very easily updated to support Hyperapp 2.0 when it is out.