Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Deeply nested routes #257

Closed
neutraali opened this issue Sep 16, 2022 · 4 comments
Closed

Deeply nested routes #257

neutraali opened this issue Sep 16, 2022 · 4 comments
Labels
V3 Features that won't be released in v2, but planned for the next major release

Comments

@neutraali
Copy link

Following the docs for nested routes, it seems to be hinted at that you can nest routes logically:

<Router base="/app">
	<NestedRoutes base="/dashboard">
		{/* the real url is /app/dashboard/users */}
		<Link to="/users" />
		<Route path="/users" />
	</NestedRoutes>
</Router>

However, when trying things out in the demo sandbox, this doesn't seem to be the case. Perhaps I'm doing something wrong?

Steps to reproduce

  1. Add a link to /other to the navigation list under <Scope base='help'>.
  2. Add <Scope base="/other"><p>Example text</p></Scope> above <Route path="/topics">.

Expected result:

<p>Example text</p> is rendered (like /topics and /how-to) at /help/other.

Actual result:

<p>Example text</p> is not rendered at /help/other.

You can achieve a similar scenario by wrapping the main <div className="App"> with <Router base='/app'>. This will render everything up to /help normally. There seems to be a bit of confusion as to how to achieve nested routes beyond the first level.

I'd appreciate any help regarding the matter! We're trying to transition away from React Router and its backward-facing development.

@waful
Copy link

waful commented Oct 2, 2022

The reason why your steps to reproduce does not work in the sandbox is fundamentally caused by the same behavior (not necessarily bug) of useLocation as my issue #244: useLocation returns the current path starting from the nearest base path not including the base path itself. The sandbox defines a Scope component with this line at line 14 to prevent render:

if (!parentLocation.startsWith(nestedBase)) return null;

parentLocation comes from useLocation which yields /other but nestedBase is actually /help/other, so <Scope base="/other"> renders null.

My gut feeling is when the base path feature was implemented, it was not anticipated that there would be nested base paths and the current wouter version does not support it.

@MehYam
Copy link

MehYam commented Oct 16, 2022

I worked around this with a slight variation in his example - instead of checking against the entire base path, my nested router checks only the current one:

function NestedRouter({ path, children }: NestedRouterProps) {
    const router = useRouter();
    const [location] = useLocation();
    return location.startsWith(path) ? <Router base={router.base + path}>{children}</Router> : null;
}

This lets you build arbitrarily nested structures that only know about their own level in the path (arguably, the 80% of what people really want):

            <NestedRouter path='/level1'>
                <Link to='/level2'>level2</Link><br />
                <NestedRouter path='/level2'>
                    <Link to='/level3'>level3</Link><br />
                    <NestedRouter path='/level3'>
                        <Link to='/doc1'>doc 1</Link> <Link to='/doc2'>doc 2 (has subdocs)</Link><br />
                        ...etc...

I also made my own Switch variant which works with these, let me know if you're interested.

@molefrog molefrog added the V3 Features that won't be released in v2, but planned for the next major release label Nov 2, 2022
@waful
Copy link

waful commented Nov 2, 2022

I dug into it a little deeper and realized that while the use-location.js constructor supports a base option, it is never used. In index.js, buildRouter uses locationHook as is without any options. So is this a simple matter of incomplete implementation? I was able to get the NestedRoutes example working replacing the useLocation value with window.location.pathname, but obviously reading pathname from window.location causes issues with not triggering rerenders.

@molefrog
Copy link
Owner

Fixed in #265

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
V3 Features that won't be released in v2, but planned for the next major release
Projects
None yet
Development

Successfully merging a pull request may close this issue.

4 participants