wouter
wouter copied to clipboard
Make a more robust nested routing structure possible
Here's my basic idea. Fixes #225 while remaining fully backwards compatible. Alternative to #226. For the nested router use-case, it will now be possible to do:
function NestedRouter(props) {
return <Router {...props} parent={useRouter()}/>
}
If this PR gets some traction, I can update type definitions as needed.
FYI, this PR will also allow some really cool stuff like a stable useNavigate function relative to your current router context. E.g.:
const useNavigateFromRouterContext = (ctx: RouterProps) => React.useCallback(
(to: Path, options?: {replace?: boolean}) => {
window.history[options?.replace ? "replaceState" : "pushState"](null, "",
to[0] === "~" ? to.slice(1) :
ctx.base + (to && !to.startsWith('/') && !ctx.base.endsWith('/') ? `/${to}` : to))
}, [ctx]); // Do NOT depend on ctx.base! Unreliable, and also will cause this callback to un-memoize.
export const useNavigate = () => useNavigateFromRouterContext(useRouter());
@molefrog any thoughts on this PR? I can update the type definitions and stuff if you like my changes.
I was about to begrudgingly switch to react-router but this PR makes me think I should wait! I'll be keeping an eye on this PR because it's something that I really need in my current project. Props to @HansBrende for the great idea
Hey @HansBrende. It took me a while to wrap my head around your solution, it was really smart and nice approach, however there was something in the API design that was bothering me.
I realised that we could get the closest parent router from the context, and also assume that routers are immutable — they actually never change within a particular component node, even if <Router /> starts receiving different props, in reality it's really hard to handle these updates, mostly because it could lead to some weird behaviour (imagine that you try to change the hook, it'll break the app).
Would you mind taking a look at #265? It also gave some nice size reduction.
Closing in favour of #265