MithrilJS / mithril.js

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

Replace m.route by a Router component #2587

Closed andershol closed 5 days ago

andershol commented 4 years ago

Is this something you're interested in implementing yourself? No

Description

This is just a rough idea. Maybe it would be useful to instead of writing m.route(document.body, "/page1", { "/page1": Page1 }); to be able to write something like: m.mount(document.body, { view: () => m(Router, { default: '/page1', routes: { "/page1": Page1 } }) }); such that routing could be done inside layouts and not only at the top level. It might also allow routing to be split into components and nested.

A larger sample (the implementation is a quick hack), tested in Firefox and chrome:

Why

Sample 3 is my motivation. It seems to me that I in this case want to not have the routing on the top level, but instead inside the layout. Some of the motivation is that it seems that the diff-algorithm will not (refer to sample 1) match up the Layout component used in Page1 to the Layout component used in Page2, so the Layout is not updated, but removed and replaced, making animation of the content imposible.

Open Questions

It seems the implementation could be made less hackish if there was a onafterview method, that was called after all child view methods had been called, or if the view method for the child components was called by the m-method (i.e. so the view methods for the child components was called and completed inside the parent view method). The use of target:'_Self' is a hack (that at least work in Firefox and Chrome) to have m.route.Link use the href and not its own onclick as the onclick use a new value for m.route.prefix, not the one used to set href.

kczx3 commented 4 years ago

I believe rewriting the router to fit your idea has been discussed and hopefully is an aim for v3. Mithril desperately needs nestable routing imho

EDIT: Fixed a horrendous typo

cavemansspa commented 4 years ago

@andershol -- not sure if it addresses your specific issue, but you can manage page transitions at the layout level. see this gitter message for link to flems example.

re:

Some of the motivation is that it seems that the diff-algorithm will not (refer to sample 1) match up the Layout component used in Page1 to the Layout component used in Page2, so the Layout is not updated, but removed and replaced, making animation of the content imposible.

here's your flems augmented

andershol commented 4 years ago

not sure if it addresses your specific issue, but you can manage page transitions at the layout level. see this gitter message for link to flems example.

Thanks for the pointer. I tried to simplify it a bit (to use css-transitions, and when it is assumed that there will be exactly one TransitionLayout on each page by only handling a single outbound/inbound and by starting slide in oncreate, you don't need to hook into the mithril resolveRoute, but can just update stack and check for direction in oncreate). This handles a bit of a different part of the issue, than what I was talking about. But of course it is related and something I also need to implement. I think that approach is to simple however, as it does not seem to handle deep links and I think I want a more "app like" behavior where the back button takes you up the the navigation hierarchy, but not down or sideways (while supporting "sub tasks", I guess), so some knowledge of the navigation hierarchy is required. So I think adding a "direction" to mithril wouldn't really make sense, but a before/after route event on the m.route would be nice. But that is another issue I guess.

Some of the motivation is that it seems that the diff-algorithm will not (refer to sample 1) match up the Layout component used in Page1 to the Layout component used in Page2, so the Layout is not updated, but removed and replaced, making animation of the content imposible.

here's your flems augmented

So what you are saying is that the diff-algorithm handles the individual elements inside a route-resolver, but not inside a component. Thanks for pointing that out. I had not payed attention to that distinction, although in hindsight I guess I used that in another project.

dead-claudia commented 4 years ago

We are currently looking into this. #2281 is closed, but that's the general direction we've been looking. (Currently, our route resolvers haven't been paying off super well.)

Full component-driven routing is unlikely to occur until we get React-like context (#2148), but this is a space we've been exploring.

kczx3 commented 4 years ago

Would you happen to have a status on where you’re at with “looking into this”?

dead-claudia commented 4 years ago

There's #2281 (closed for other reasons), but the current state of my design work is here. There's no official timeline, but there's two main blockers:

  1. React-like context is a necessity if you want these routes to be testable.
  2. I want it to have both React Router's flexibility and Mithril's simplicity, and that's not easy at all.
kczx3 commented 4 years ago

@isiahmeadows Thanks for pointing to this. It was an interesting read. Although, for someone being less theoretical in their thinking, it would be beneficial to have some sudo code along with the API to see how code might look using that API.

dead-claudia commented 4 years ago

@kczx3 Here's a couple small concrete examples: 1, 2

Neither are actually runnable - they're just examples.

kczx3 commented 4 years ago

Thank you!