javascript - Nästlade rutter med react router v4/v5


Jag har för närvarande problem med att nidöa rutter med React Router v4.

Det närmaste exemplet var ruttkonfigurationen i React-Router v4-dokumentationen.

Jag vill dela upp min app i två olika delar.

En frontend och ett administrationsområde.

Jag tänkte på något sådant här:

<Match pattern="/" component={Frontpage}>
  <Match pattern="/home" component={HomePage} />
  <Match pattern="/about" component={AboutPage} />
</Match>
<Match pattern="/admin" component={Backend}>
  <Match pattern="/home" component={Dashboard} />
  <Match pattern="/users" component={UserPage} />
</Match>
<Miss component={NotFoundPage} />

Frontend har en annan layout och stil än adminområdet. Så inom startsidan bör rutterna home, about och så vidare vara barnrutter.

/home bör renderas i Frontpage-komponenten och /admin/home bör renderas inom Backend-komponenten.

Jag provade några andra varianter men jag hamnade alltid med att inte träffa /home eller /admin/home.

Svar #1

I react-router-v4 nästlar du inte <Routes />. Istället placerar du dem inuti en annan <Component />.

Till exempel

<Route path='/topics' component={Topics}>
  <Route path='/topics/:topicId' component={Topic} />
</Route>

bör bli

<Route path='/topics' component={Topics} />

med

const Topics = ({ match }) => (
  <div>
    <h2>Topics</h2>
    <Link to={`${match.url}/exampleTopicId`}>
      Example topic
    </Link>
    <Route path={`${match.path}/:topicId`} component={Topic}/>
  </div>
) 

Här är ett grundläggande exempel direkt från react-router-dokumentationen.

Svar #2

react-router v6

Uppdatering för 2022 - v6 har nästlade Route-komponenter som bara fungerar™.

Denna fråga handlar om v4/v5, men det bästa svaret nu är använd bara v6 om du kan!

Se exempel på kod i detta blogginlägg. Om du inte kan uppgradera än, dock...

react-router v4 & v5

Det är sant att för att nästla Routes behöver du placera dem i barnkomponenten av Route.

Men om du föredrar en mer inline-syntax istället för att dela upp dina Routes över komponenter, kan du tillhandahålla en funktionell komponent till render-egenskapen för den Route du vill nestla under.

<BrowserRouter>

  <Route path="/" component={Frontpage} exact />
  <Route path="/home" component={HomePage} />
  <Route path="/about" component={AboutPage} />

  <Route
    path="/admin"
    render={({ match: { url } }) => (
      <>
        <Route path={`${url}/`} component={Backend} exact />
        <Route path={`${url}/home`} component={Dashboard} />
        <Route path={`${url}/users`} component={UserPage} />
      </>
    )}
  />

</BrowserRouter>

Om du är intresserad av varför render-prop bör användas och inte component-prop, är det för att det stoppar den inbyggda funktionella komponenten från att monteras om vid varje renderering. Se dokumentationen för mer detaljer.

Observera att exemplet omsluter de inbäddade Routes i en Fragment. Före React 16 kan du istället använda en behållare <div>.

Svar #3

Ville bara nämna att react-router v4 har förändrats radikalt sedan denna fråga ställdes/svarades.

Det finns inte längre någon <Match>-komponent! <Switch> används för att säkerställa att endast den första matchen renderas. <Redirect> ja .. omdirigerar till en annan rutt. Använd eller utelämna exact för att antingen inkludera eller exkludera en delvis match.

Se dokumentationen. Den är fantastisk. https://reacttraining.com/react-router/

Här är ett exempel som jag hoppas är användbart för att svara på din fråga.

<Router>
  <div>
    <Redirect exact from='/' to='/front'/>
    <Route path="/" render={() => {
      return (
        <div>
          <h2>Home menu</h2>
          <Link to="/front">front</Link>
          <Link to="/back">back</Link>
        </div>
      );
    }} />          
    <Route path="/front" render={() => {
      return (
        <div>
        <h2>front menu</h2>
        <Link to="/front/help">help</Link>
        <Link to="/front/about">about</Link>
        </div>
      );
    }} />
    <Route exact path="/front/help" render={() => {
      return <h2>front help</h2>;
    }} />
    <Route exact path="/front/about" render={() => {
      return <h2>front about</h2>;
    }} />
    <Route path="/back" render={() => {
      return (
        <div>
        <h2>back menu</h2>
        <Link to="/back/help">help</Link>
        <Link to="/back/about">about</Link>
        </div>
      );
    }} />
    <Route exact path="/back/help" render={() => {
      return <h2>back help</h2>;
    }} />
    <Route exact path="/back/about" render={() => {
      return <h2>back about</h2>;
    }} />
  </div>
</Router>

Hoppas det hjälpte, låt mig veta. Om detta exempel inte svarar på din fråga tillräckligt bra, säg till så ska jag se om jag kan ändra det.

Svar #4

Jag lyckades definiera nästlade rutter genom att omsluta med Switch och definiera den nästlade rutten före rot-rutten.

<BrowserRouter>
  <Switch>
    <Route path="/staffs/:id/edit" component={StaffEdit} />
    <Route path="/staffs/:id" component={StaffShow} />
    <Route path="/staffs" component={StaffIndex} />
  </Switch>
</BrowserRouter>

Referens: https://github.com/ReactTraining/react-router/blob/master/packages/react-router/docs/api/Switch.md

Svar #5

Att använda hooks

Den senaste uppdateringen med hooks är att använda useRouteMatch.

Huvudruttningskomponent

export default function NestingExample() {
  return (
    <Router>
      <Switch>
       <Route path="/topics">
         <Topics />
       </Route>
     </Switch>
    </Router>
  );
}

Barnkomponent

function Topics() {
  // The `path` lets us build <Route> paths 
  // while the `url` lets us build relative links.

  let { path, url } = useRouteMatch();

  return (
    <div>
      <h2>Topics</h2>
      <h5>
        <Link to={`${url}/otherpath`}>/topics/otherpath/</Link>
      </h5>
      <ul>
        <li>
          <Link to={`${url}/topic1`}>/topics/topic1/</Link>
        </li>
        <li>
          <Link to={`${url}/topic2`}>/topics/topic2</Link>
        </li>
      </ul>

      // You can then use nested routing inside the child itself
      <Switch>
        <Route exact path={path}>
          <h3>Please select a topic.</h3>
        </Route>
        <Route path={`${path}/:topicId`}>
          <Topic />
        </Route>
        <Route path={`${path}/otherpath`>
          <OtherPath/>
        </Route>
      </Switch>
    </div>
  );
}

Relaterade artiklar