具有反应路由器v4的嵌套路由

dat*_*oml 240 javascript nested reactjs react-router react-router-v4

我目前正在使用react router v4进行嵌套路由.

最接近的示例是React-Router v4文档中的路由配置 .

我想将我的应用程序拆分为两个不同的部分.

前端和管理区域.

我在考虑这样的事情:

<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} />
Run Code Online (Sandbox Code Playgroud)

前端具有与管理区域不同的布局和样式.因此,在首页的路线回家,约一个应该是儿童路线.

/ home应该呈现在Frontpage组件中,而/ admin/home应该在Backend组件中呈现.

我尝试了一些变化,但我总是在没有击中/ home或/ admin/home.

编辑 - 19.04.2017

因为这篇文章现在有很多观点我用最终解决方案更新了它.我希望它对某人有帮助.

编辑 - 08.05.2017

删除旧解决方案

最终解决方案

这是我现在使用的最终解决方案.此示例还有一个全局错误组件,如传统的404页面.

import React, { Component } from 'react';
import { Switch, Route, Redirect, Link } from 'react-router-dom';

const Home = () => <div><h1>Home</h1></div>;
const User = () => <div><h1>User</h1></div>;
const Error = () => <div><h1>Error</h1></div>

const Frontend = props => {
  console.log('Frontend');
  return (
    <div>
      <h2>Frontend</h2>
      <p><Link to="/">Root</Link></p>
      <p><Link to="/user">User</Link></p>
      <p><Link to="/admin">Backend</Link></p>
      <p><Link to="/the-route-is-swiggity-swoute">Swiggity swooty</Link></p>
      <Switch>
        <Route exact path='/' component={Home}/>
        <Route path='/user' component={User}/>
        <Redirect to={{
          state: { error: true }
        }} />
      </Switch>
      <footer>Bottom</footer>
    </div>
  );
}

const Backend = props => {
  console.log('Backend');
  return (
    <div>
      <h2>Backend</h2>
      <p><Link to="/admin">Root</Link></p>
      <p><Link to="/admin/user">User</Link></p>
      <p><Link to="/">Frontend</Link></p>
      <p><Link to="/admin/the-route-is-swiggity-swoute">Swiggity swooty</Link></p>
      <Switch>
        <Route exact path='/admin' component={Home}/>
        <Route path='/admin/user' component={User}/>
        <Redirect to={{
          state: { error: true }
        }} />
      </Switch>
      <footer>Bottom</footer>
    </div>
  );
}

class GlobalErrorSwitch extends Component {
  previousLocation = this.props.location

  componentWillUpdate(nextProps) {
    const { location } = this.props;

    if (nextProps.history.action !== 'POP'
      && (!location.state || !location.state.error)) {
        this.previousLocation = this.props.location
    };
  }

  render() {
    const { location } = this.props;
    const isError = !!(
      location.state &&
      location.state.error &&
      this.previousLocation !== location // not initial render
    )

    return (
      <div>
        {          
          isError
          ? <Route component={Error} />
          : <Switch location={isError ? this.previousLocation : location}>
              <Route path="/admin" component={Backend} />
              <Route path="/" component={Frontend} />
            </Switch>}
      </div>
    )
  }
}

class App extends Component {
  render() {
    return <Route component={GlobalErrorSwitch} />
  }
}

export default App;
Run Code Online (Sandbox Code Playgroud)

Lyu*_*mir 279

在react-router-v4中,您不会嵌套<Routes />.相反,你把它们放在另一个里面<Component />.


例如

<Route path='/topics' component={Topics}>
  <Route path='/topics/:topicId' component={Topic} />
</Route>
Run Code Online (Sandbox Code Playgroud)

应该成为

<Route path='/topics' component={Topics} />
Run Code Online (Sandbox Code Playgroud)

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

这是一个直接来自react-router 文档基本示例.

  • 看起来很荒谬你不能只是`to ="exampleTopicId"`与`$ {match.url}`是隐含的. (10认同)
  • 你能把Topics组件变成一个类吗?'匹配'参数在哪里?在render()? (8认同)
  • 您可以为每个文档https://reacttraining.com/react-router/web/example/route-config提供嵌套路由.这将允许根据文档中的主题进行集中路由配置.想想如果不可用的话,在一个更大的项目中管理是多么疯狂. (7认同)
  • 谢谢@leo,我在道具中访问了'匹配' (3认同)
  • 这些都不是嵌套的路线,它仍然使用render路由这需要的功能部件作为输入的属性的一电平的路由,外观更加仔细,存在反应路由器的意义上没有嵌套<4. RouteWithSubRoutes是一-level使用模式匹配的路由列表. (3认同)

dav*_*wil 73

确实,为了嵌套路由,您需要将它们放在Route的子组件中.

但是,如果您更喜欢更"内联"的语法而不是跨组件断开路由,则可以使用内嵌无状态功能组件来嵌入要嵌套的render支柱render,如下所示:

<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>
Run Code Online (Sandbox Code Playgroud)

如果您对为什么component应该使用而不是感兴趣<div>,那就是停止在每个渲染上重新安装内联组件.有关详细信息,请参阅文档.

另请注意,上面的示例使用React 16 Fragments来包装嵌套的Routes,只是为了使它更清晰.在React 16之前,你可以在render这里使用容器.

  • 感谢上帝唯一的解决方案,清晰,可持续,并按预期工作.我希望反应路由器3嵌套的路由回来了. (11认同)
  • 您应该使用`match.path`而不是`match.url`。前者通常在Route`path`属性中使用;当您推一条新路线时(例如,链接“至”道具) (2认同)

jar*_*m1r 47

只是想提一下,自从这个问题被发布/回答后,react-router v4发生了根本性的变化.

没有<Match>组件了!<Switch>是确保只渲染第一个匹配.<Redirect>好..重定向到另一条路线.使用或省略exact部分匹配或排除部分匹配.

查看文档.他们都是伟大的.https://reacttraining.com/react-router/

这是一个我希望可以回答你的问题的例子.

  <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>
Run Code Online (Sandbox Code Playgroud)

希望它有所帮助,让我知道.如果这个例子没有足够好地回答你的问题,请告诉我,我会看看是否可以修改它.

  • @Ville 我很惊讶;你找到更好的解决方案了吗?我不想到处都有路线,天哪 (4认同)
  • 我是否正确理解没有嵌套/子路线(再也没有)?我需要在所有路线中复制基本路线吗?没有反应 - 路由器4以可维护的方式为构建路由提供任何帮助吗? (2认同)

asu*_*aaa 11

我通过Switch在根路由之前使用并定义嵌套路由成功地定义了嵌套路由。

<BrowserRouter>
  <Switch>
    <Route path="/staffs/:id/edit" component={StaffEdit} />
    <Route path="/staffs/:id" component={StaffShow} />
    <Route path="/staffs" component={StaffIndex} />
  </Switch>
</BrowserRouter>
Run Code Online (Sandbox Code Playgroud)

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

  • 请注意,虽然此解决方案适合某些情况,但它不适用于使用嵌套路由呈现分层布局组件的情况,这是您可以在 v3 中使用嵌套路由做的好事之一。 (2认同)

小智 7

使用钩子

钩子的最新更新是使用useRouteMatch.

主路由组件


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

子组件

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

Run Code Online (Sandbox Code Playgroud)


小智 6

像这样的东西。

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;
Run Code Online (Sandbox Code Playgroud)


for*_*d04 5

反应路由器v6

允许使用嵌套路由(如 v3)和单独的分割路由(v4、v5)。

嵌套路由

将中小型应用程序的所有路由保留在一处:

<Routes>
  <Route path="/" element={<Home />} >
    <Route path="user" element={<User />} /> 
    <Route path="dash" element={<Dashboard />} /> 
  </Route>
</Routes>
Run Code Online (Sandbox Code Playgroud)

<Routes>
  <Route path="/" element={<Home />} >
    <Route path="user" element={<User />} /> 
    <Route path="dash" element={<Dashboard />} /> 
  </Route>
</Routes>
Run Code Online (Sandbox Code Playgroud)
const App = () => {
  return (
    <BrowserRouter>
      <Routes>
        // /js is start path of stack snippet
        <Route path="/js" element={<Home />} >
          <Route path="user" element={<User />} />
          <Route path="dash" element={<Dashboard />} />
        </Route>
      </Routes>
    </BrowserRouter>
  );
}

const Home = () => {
  const location = useLocation()
  return (
    <div>
      <p>URL path: {location.pathname}</p>
      <Outlet />
      <p>
        <Link to="user" style={{paddingRight: "10px"}}>user</Link>
        <Link to="dash">dashboard</Link>
      </p>
    </div>
  )
}

const User = () => <div>User profile</div>
const Dashboard = () => <div>Dashboard</div>

ReactDOM.render(<App />, document.getElementById("root"));
Run Code Online (Sandbox Code Playgroud)

替代方案:通过 . 将您的路由定义为纯 JavaScript 对象useRoutes

分开的路线

您可以使用单独的路由来满足较大应用程序的要求,例如代码分割:

// inside App.jsx:
<Routes>
  <Route path="/*" element={<Home />} />
</Routes>

// inside Home.jsx:
<Routes>
  <Route path="user" element={<User />} />
  <Route path="dash" element={<Dashboard />} />
</Routes>
Run Code Online (Sandbox Code Playgroud)

<div id="root"></div>
    <script src="https://unpkg.com/react@16.13.1/umd/react.production.min.js"></script>
    <script src="https://unpkg.com/react-dom@16.13.1/umd/react-dom.production.min.js"></script>
    <script src="https://unpkg.com/history@5.0.0/umd/history.production.min.js"></script>
    <script src="https://unpkg.com/react-router@6.0.0-alpha.5/umd/react-router.production.min.js"></script>
    <script src="https://unpkg.com/react-router-dom@6.0.0-alpha.5/umd/react-router-dom.production.min.js"></script>
    <script>var { BrowserRouter, Routes, Route, Link, Outlet, useNavigate, useLocation } = window.ReactRouterDOM;</script>
Run Code Online (Sandbox Code Playgroud)
// inside App.jsx:
<Routes>
  <Route path="/*" element={<Home />} />
</Routes>

// inside Home.jsx:
<Routes>
  <Route path="user" element={<User />} />
  <Route path="dash" element={<Dashboard />} />
</Routes>
Run Code Online (Sandbox Code Playgroud)


小智 5

React Router v6 或版本 6 的完整答案,以防万一。

import Dashboard from "./dashboard/Dashboard";
import DashboardDefaultContent from "./dashboard/dashboard-default-content";
import { Route, Routes } from "react-router";
import { useRoutes } from "react-router-dom";

/*Routes is used to be Switch*/
const Router = () => {

  return (
    <Routes>
      <Route path="/" element={<LandingPage />} />
      <Route path="games" element={<Games />} />
      <Route path="game-details/:id" element={<GameDetails />} />
      <Route path="dashboard" element={<Dashboard />}>
        <Route path="/" element={<DashboardDefaultContent />} />
        <Route path="inbox" element={<Inbox />} />
        <Route path="settings-and-privacy" element={<SettingsAndPrivacy />} />
        <Route path="*" element={<NotFound />} />
      </Route>
      <Route path="*" element={<NotFound />} />
    </Routes>
  );
};
export default Router;
Run Code Online (Sandbox Code Playgroud)
import DashboardSidebarNavigation from "./dashboard-sidebar-navigation";
import { Grid } from "@material-ui/core";
import { Outlet } from "react-router";

const Dashboard = () => {
  return (
    <Grid
      container
      direction="row"
      justify="flex-start"
      alignItems="flex-start"
    >
      <DashboardSidebarNavigation />
      <Outlet />
    </Grid>
  );
};

export default Dashboard;
Run Code Online (Sandbox Code Playgroud)

Github 仓库在这里。https://github.com/webmasterdevlin/react-router-6-demo