Nested routes with react router v4 / v5

后端 未结 11 1879
广开言路
广开言路 2020-11-22 12:34

I am currently struggling with nesting routes using react router v4.

The closest example was the route config in the React-Router v4 Documentation.

I want t

相关标签:
11条回答
  • 2020-11-22 13:07

    Some thing like this.

    import React from 'react';
    import {
      BrowserRouter as Router, Route, NavLink, Switch, Link
    } from 'react-router-dom';
    
    import '../assets/styles/App.css';
    
    const Home = () =>
      <NormalNavLinks>
        <h1>HOME</h1>
      </NormalNavLinks>;
    const About = () =>
      <NormalNavLinks>
        <h1>About</h1>
      </NormalNavLinks>;
    const Help = () =>
      <NormalNavLinks>
        <h1>Help</h1>
      </NormalNavLinks>;
    
    const AdminHome = () =>
      <AdminNavLinks>
        <h1>root</h1>
      </AdminNavLinks>;
    
    const AdminAbout = () =>
      <AdminNavLinks>
        <h1>Admin about</h1>
      </AdminNavLinks>;
    
    const AdminHelp = () =>
      <AdminNavLinks>
        <h1>Admin Help</h1>
      </AdminNavLinks>;
    
    
    const AdminNavLinks = (props) => (
      <div>
        <h2>Admin Menu</h2>
        <NavLink exact to="/admin">Admin Home</NavLink>
        <NavLink to="/admin/help">Admin Help</NavLink>
        <NavLink to="/admin/about">Admin About</NavLink>
        <Link to="/">Home</Link>
        {props.children}
      </div>
    );
    
    const NormalNavLinks = (props) => (
      <div>
        <h2>Normal Menu</h2>
        <NavLink exact to="/">Home</NavLink>
        <NavLink to="/help">Help</NavLink>
        <NavLink to="/about">About</NavLink>
        <Link to="/admin">Admin</Link>
        {props.children}
      </div>
    );
    
    const App = () => (
      <Router>
        <div>
          <Switch>
            <Route exact path="/" component={Home}/>
            <Route path="/help" component={Help}/>
            <Route path="/about" component={About}/>
    
            <Route exact path="/admin" component={AdminHome}/>
            <Route path="/admin/help" component={AdminHelp}/>
            <Route path="/admin/about" component={AdminAbout}/>
          </Switch>
    
        </div>
      </Router>
    );
    
    
    export default App;

    0 讨论(0)
  • 2020-11-22 13:11

    You can try something like Routes.js

    import React, { Component } from 'react'
    import { BrowserRouter as Router, Route } from 'react-router-dom';
    import FrontPage from './FrontPage';
    import Dashboard from './Dashboard';
    import AboutPage from './AboutPage';
    import Backend from './Backend';
    import Homepage from './Homepage';
    import UserPage from './UserPage';
    class Routes extends Component {
        render() {
            return (
                <div>
                    <Route exact path="/" component={FrontPage} />
                    <Route exact path="/home" component={Homepage} />
                    <Route exact path="/about" component={AboutPage} />
                    <Route exact path="/admin" component={Backend} />
                    <Route exact path="/admin/home" component={Dashboard} />
                    <Route exact path="/users" component={UserPage} />    
                </div>
            )
        }
    }
    
    export default Routes
    

    App.js

    import React, { Component } from 'react';
    import logo from './logo.svg';
    import './App.css';
    import { BrowserRouter as Router, Route } from 'react-router-dom'
    import Routes from './Routes';
    
    class App extends Component {
      render() {
        return (
          <div className="App">
          <Router>
            <Routes/>
          </Router>
          </div>
        );
      }
    }
    
    export default App;
    

    I think you can achieve the same from here also.

    0 讨论(0)
  • 2020-11-22 13:13

    react-router v6

    An update for 2020: The upcoming v6 release will have nested Route components that Just Work™. See example code in this blog post.

    While the original question is about v4/v5, the right answer when v6 ships will be just use that if you can. It's currently in beta.


    react-router v4 & v5

    It's true that in order to nest Routes you need to place them in the child component of the Route.

    However if you prefer a more inline syntax rather than breaking your Routes up across components, you can provide a functional component to the render prop of the Route you want to nest 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>
    

    If you're interested in why the render prop should be used, and not the component prop, it's because it stops the inline functional component from being remounted on every render. See the documentation for more detail.

    Note that the example wraps the nested Routes in a Fragment. Prior to React 16, you can use a container <div> instead.

    0 讨论(0)
  • 2020-11-22 13:21

    Just wanted to mention react-router v4 changed radically since this question was posted/answed.

    There is no <Match> component any more! <Switch>is to make sure only the first match is rendered. <Redirect> well .. redirects to another route. Use or leave out exact to either in- or exclude a partial match.

    See the docs. They are great. https://reacttraining.com/react-router/

    Here's an example I hope is useable to answer your question.

    <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>
    

    Hope it helped, let me know. If this example is not answering your question well enough, tell me and I'll see if I can modify it.

    0 讨论(0)
  • 2020-11-22 13:21

    A complete answer for React Router v5.

    
    const Router = () => {
      return (
        <Switch>
          <Route path={"/"} component={LandingPage} exact />
          <Route path={"/games"} component={Games} />
          <Route path={"/game-details/:id"} component={GameDetails} />
          <Route
            path={"/dashboard"}
            render={({ match: { path } }) => (
              <Dashboard>
                <Switch>
                  <Route
                    exact
                    path={path + "/"}
                    component={DashboardDefaultContent}
                  />
                  <Route path={`${path}/inbox`} component={Inbox} />
                  <Route
                    path={`${path}/settings-and-privacy`}
                    component={SettingsAndPrivacy}
                  />
                  <Redirect exact from={path + "/*"} to={path} />
                </Switch>
              </Dashboard>
            )}
          />
          <Route path="/not-found" component={NotFound} />
          <Redirect exact from={"*"} to={"/not-found"} />
        </Switch>
      );
    };
    
    export default Router;
    
    const Dashboard = ({ children }) => {
      return (
        <Grid
          container
          direction="row"
          justify="flex-start"
          alignItems="flex-start"
        >
          <DashboardSidebarNavigation />
          {children}
        </Grid>
      );
    };
    
    export default Dashboard;
    

    Github repo is here. https://github.com/webmasterdevlin/react-router-5-demo

    0 讨论(0)
  • 2020-11-22 13:23
    interface IDefaultLayoutProps {
        children: React.ReactNode
    }
    
    const DefaultLayout: React.SFC<IDefaultLayoutProps> = ({children}) => {
        return (
            <div className="DefaultLayout">
                {children}
            </div>
        );
    }
    
    
    const LayoutRoute: React.SFC<IDefaultLayoutRouteProps & RouteProps> = ({component: Component, layout: Layout, ...rest}) => {
    const handleRender = (matchProps: RouteComponentProps<{}, StaticContext>) => (
            <Layout>
                <Component {...matchProps} />
            </Layout>
        );
    
        return (
            <Route {...rest} render={handleRender}/>
        );
    }
    
    const ScreenRouter = () => (
        <BrowserRouter>
            <div>
                <Link to="/">Home</Link>
                <Link to="/counter">Counter</Link>
                <Switch>
                    <LayoutRoute path="/" exact={true} layout={DefaultLayout} component={HomeScreen} />
                    <LayoutRoute path="/counter" layout={DashboardLayout} component={CounterScreen} />
                </Switch>
            </div>
        </BrowserRouter>
    );
    
    0 讨论(0)
提交回复
热议问题