newguy
newguy

Reputation: 5976

React Router v4 dynamic nested routes do not match

I ask this question just want to make sure that I understand the dynamic nested routes in React Router v4 correctly. I want to build a hacker news client similar to this one. But I am bogged down by setting up the dynamic routes.

In React Router v4, if I follow other tutorials on the web using the match object I will have something like this (A super simple one):

const ChildComponent = ({rows, match}) => (
  <div>
    <ol>
      rows.map((row, i) => {
        return (
           <li key={row.id}>
            <a href={row.url}>row.title</a> // topic title
            <Link to=`${match.url}/${row.by}`>row.by</Link> // topic author
           </li>

        )
      }
    </ol>
    <Route path=`${match.url}/:userId` render={(props) => <UserProfile fetchUserData={fetchUserData} {...props} />} />
  </div>
)};

And when we render the parent component, we usually use something like this for routing:

<Switch>
    <Route path="/" render={Home} />
    <Route path="/topics" render={(props) => <ChildComponent rows={rows} {...props} /> } />
    <Route path="*" render={() => <div>Not Found</div>} />
</Switch>

But this is not ideal for this case, as when I click to view the author's info I need to display a url like this: "http://mysite/user/userid" instead of the current one which is "http://mysite/news/userid".

However, if I change ${match.url}/${row.by} to /user/${row.by} and change ${match.url}/:userId to /user/:userId the route is not recognized in the app. The route begins with /user/ is simply skipped, it will go straight to the app's NotFound route (if there is one), which is in the parent component. Why will the links in child component try to match the routes in the parent if I don't use ${match.url} in the route?

I have added a demo for you to easier to understand this problem.

Upvotes: 0

Views: 1028

Answers (1)

ChrisR
ChrisR

Reputation: 4008

Because when you'll click the /user/:userId: link the app will parse the Router's Switch to see if something matches. If it doesn't it fallback to *. In your case, you did not specify anything in the Switch to handle /user .

You'll need to move your userId Route declaration to the Switch as they won't share the same first route (/user !== /topics).

<Switch>
    <Route path="/" render={Home} />
    <Route path="/topics" render={(props) => <ChildComponent rows={rows} {...props} /> } />
    <Route path="/user/:userId" render={(props) => <UserProfile fetchUserData={fetchUserData} {...props} />} />
    <Route render={() => <div>Not Found</div>} />
</Switch>

Upvotes: 1

Related Questions