Replies: 1 comment 1 reply
-
is it something like angular router: |
Beta Was this translation helpful? Give feedback.
1 reply
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
TLDR; It would be nice with a way to have sibling
<Outlet>
s.This is an idea that touches on SSR data fetching, app layout architecture and a bunch of other things. It's an idea with tons of context, history, prior art, caveats and other complexity. I could write a book about it, but I'll try to keep this to an overview, so I'm necessarily leaving a lot of detail out, feel free to ask for follow ups where I've missed things! 😄
Background
One of React Routers great features is nested routes, being able to drop in a
<Route>
in any component is a really powerful thing. A cool aspect of that, which gets some love in v6 since it's lifted to core, is how a centralized route configuration can still have nested routes in it. This is powerful for a couple of reasons, but for me a central one is how having a url and matching that to the config will give back all of those components that matches and will have to be rendered for that route. This has let us build a structure on top of v5 where any component in the route configuration can have it's own "getInitialProps/preload
"-function that works seamlessly with SSR, meaning we can move data fetching closer to where the data is used, providing for better separation of concerns and other benefits.Current challenges
Imagine this example:
If we want to convert this to a centralized route config and focus on just the
ArticlePageMainSection
first, we would get something like this:In reality, there might be a bunch of layers to drill children down through which can be cumbersome. It seems as if the new v6
<Outlet>
-component solves this (🎉), since it seems to rely on context and thus can be used at any point below<App>
(?):So far so good, but how do we add that
ArticlePageHeader
now that we have a centralized route config? In short, RR6 has support for this:But when hoisting those routes (which can be necessary/desired with SSR especially), something like this is not supported out of the box:
Solution
The example above might look a bit contrived, but in reality with SSR it can be really nice to have a bunch of nested routes at the same level just so those nested components can fetch data for themselves:
This is still contrived of course, but I hope it shows the general idea.
We've built a solution close to this on top of v5 and we've noticed it unlocks a bunch of interesting things.
SSR data fetching in nested components
I've mentioned this already, but this is such a powerful thing it deserves a second mention..
Slots as positions on the page
If we instead of
productOverview
,productDetails
,relatedProducts
andproductReviews
name our slots after their positions on the pageproductPageSlot1
,productPageSlot2
,productPageSlot3
andproductPageSlot4
we now have a way of changing the page layout by modifying the routes config.Route overrides
Based on the above concept, we've built a system for overriding the routes based on certain conditions.
One such condition is if the page is being rendered inside of our app (this hides the
pageHeader
andpageFooter
slots since the app renders those natively).Other conditions can be overrides as a way of having different page layouts in different countries or modifying routes and layouts as parts of a/b-tests or feature toggles, etc.
(Server Components)
This is a bit premature, but I wanted to mention it briefly anyway. SCs can render other SCs as well as client components, but client components can't ever render an SC, unless that is passed down as a "prerendered"
children
from a SC higher up in the tree.Because we can match routes ahead of time, those are perfect candidates for SCs. These could then be rendered further down in the tree inside of client components by using
<Outlet>
. Supporting multiple<Outlet>
s in sibling components seems like an extra nice thing in that scenario.This section is pretty dense because I want to keep it as an aside, so please do ask questions if you want me to expand on it.
Closing remarks
In summary, for different reasons it would be nice for a way to render sibling
<Outlet>
s somehow (in a single component or in "sibling"-isch components). API-design here is tricky, so I'm not at all sure of the best way to support it, I just wanted to put the rough idea on the table to start a discussion. I'm also aware Remix supports nested data fetching, but I'm not sure how much overlap there is there.Looking at the beta APIs, I'm pretty sure we can move our current solution over to v6 with some changes. That means things like this can be implemented in userland which is a great testament to the low level utilities of this library!
There are a bunch of downsides as well of course, here are some:
If it is desirable to move supporting sibling
Outlet
s into core, that could probably be done in a minor, but I wanted to write up the idea before a proper v6 release anyway.While the base idea is simple on the surface, the implications and nuance is complex to capture in writing, so I hope any of this writeup made any sense? 😄
Edit: A different way to describe this would be to approach it from the other side, supporting named children in
<Route>
and route configurations. Not sure which angle makes more sense to think about it from.Beta Was this translation helpful? Give feedback.
All reactions