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>
);
}
