带有react-router v4 / v5 的嵌套路由

IT技术 javascript reactjs nested react-router react-router-v4
2021-01-23 15:07:03

我目前正在努力使用 react router v4 嵌套路由。

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

我想将我的应用程序分成 2 个不同的部分。

一个前端和一个管理区域。

我在想这样的事情:

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

前端的布局和样式与管理区域不同。所以在首页的路线回家,大约等一个应该是子路线。

/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;
6个回答

在 react-router-v4 中,您不要嵌套<Routes />. 相反,您将它们放在另一个<Component />.


例如

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

应该成为

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

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

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

似乎可笑,你不能只to="exampleTopicId"${match.url}是隐含的。
2021-03-11 15:07:03
您可以根据文档reacttraining.com/react-router/web/example/route-config嵌套路由这将允许根据文档中的主题进行集中路由配置。想想如果不可用,在更大的项目中进行管理是多么疯狂。
2021-03-14 15:07:03
这些不是嵌套路由,它是一级路由,仍然使用 Route 的 render 属性,它以功能组件作为输入,仔细看,在 react router < 4 的意义上没有嵌套。 RouteWithSubRoutes 是一个使用模式匹配的路由级别列表。
2021-03-20 15:07:03
你能把Topics组件变成一个类吗?'match' 参数从何而来?在渲染()?
2021-03-22 15:07:03
我可以在基本示例中从您的链接实现,但是当我手动输入 url 时,它在我的本地主机服务器上不起作用。但它确实在你的例子中。另一方面,当我用 # 手动输入 url 时,HashRouter 可以正常工作。当我手动输入 url 时,您知道为什么在我的本地主机服务器上 BrowserRouter 不工作吗?
2021-03-24 15:07:03

react-router v6

2021更新- v6 具有RouteJust Work™ 的嵌套组件。

这个问题是关于 v4/v5,但现在最好的答案是尽可能使用 v6!

请参阅此博客文章中的示例代码但是,如果您还不能升级...

react-router v4 & v5

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

但是,如果您更喜欢更内联的语法而不是跨组件分解renderRoute,则可以为要嵌套在其下的 Routeprop提供一个功能组件

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

如果您对为什么render应该使用 prop 而不是componentprop感兴趣,那是因为它会阻止内联功能组件在每次渲染时重新安装。有关更多详细信息,请参阅文档

请注意,该示例将嵌套的 Routes 包装在Fragment 中在 React 16 之前,您可以使用容器<div>代替。

您应该使用match.path,而不是match.url前者通常用在 Routepath道具中;后者在您推送新路线时(例如 Link toprop)
2021-03-15 15:07:03
我认为嵌套路由的最佳和最简洁的解决方案
2021-03-19 15:07:03
这个完美的看起来像棱角分明的出口
2021-03-28 15:07:03
以 react-router v4/v5 为例,当有人导航到 /admin 页面时,它会呈现管理页面还是需要导航到 /admin/?谢谢!
2021-03-28 15:07:03
感谢上帝,这是唯一一种清晰、可维护且按预期工作的解决方案。我希望反应路由器 3 嵌套路由回来了。
2021-04-02 15:07:03

只是想提一下 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>
</Router>

希望它有帮助,让我知道。如果这个例子不能很好地回答你的问题,告诉我,我会看看我是否可以修改它。

我是否正确理解没有嵌套/子路由(不再)这样的东西?我需要在所有路线中复制基本路线吗?react-router 4 没有为以可维护的方式构建路由提供任何帮助吗?
2021-03-15 15:07:03
@Ville 我很惊讶;你找到更好的解决方案了吗?我不想到处都有路线,天哪
2021-03-17 15:07:03
这会起作用,但请确保在 bundle.js 的 webpack 配置中将公共路径设置为“/”,否则嵌套路由将无法在页面刷新时工作。
2021-04-09 15:07:03
有没有exactRedirect reacttraining.com/react-router/web/api/Redirect这将是一个更加简洁比<Route exact path="/" render={() => <Redirect to="/path" />} />,我做吧。至少它不会让我使用 TypeScript。
2021-04-10 15:07:03

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

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

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

请注意,虽然此解决方案适用于某些情况,但它不适用于您使用嵌套路由来呈现分层布局组件的情况,这是您可以在 v3 中使用嵌套路由做的一件好事。
2021-03-18 15:07:03
重新排列顺序解决了我的问题,尽管我不知道这是否会产生任何副作用。但现在工作..谢谢:)
2021-03-24 15:07:03

使用钩子

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

主路由组件


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

子组件

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