【问题标题】:How do I nest routes with React router如何使用 React 路由器嵌套路由
【发布时间】:2019-09-19 14:05:33
【问题描述】:

我有多个布局,应该包含不同的屏幕。每个布局都有自己的页眉、页脚和类似页面应该共享的其他内容。这是我想出的代码:

<BrowserRouter>
  <Route path={['/index', '/about']} component={BaseLayout}>
    <Route path="/index" component={Index} />
    <Route path="/about" component={About} />
  </Route>
  <Route path={['/sign-in', '/sign-up']} component={AuthLayout}>
    <Route path="/sign-in" component={SignIn} />
    <Route path="/sign-up" component={SignUp} />
  </Route>
  <Route path={['/stats'} component={DashboardLayout}>
    <Route path="/stats" component={Stats} />
  </Route>
</BrowserRouter>

上面的代码显然行不通,因为:

警告:您不应使用 &lt;Route component&gt; 和 同一路线; &lt;Route component&gt; 将被忽略

对 SO 上类似问题的回答建议直接使用包装器组件:

<BrowserRouter>
  <BaseLayout>
    <Route path="/index" component={Index} />
    <Route path="/about" component={About} />
  </BaseLayout>
  <AuthLayout>
    <Route path="/sign-in" component={SignIn} />
    <Route path="/sign-up" component={SignUp} />
  </AuthLayout>
  <DashboardLayout>
    <Route path="/stats" component={Stats} />
  </DashboardLayout>
</BrowserRouter>

这种方法的问题在于,即使它呈现单个屏幕,它也会呈现来自其他布局的元素,即,如果您在呈现在BaseLayout 内的索引页面上,您将看到来自@987654326 的元素@ 和 DashboardLayout 也是。这有点道理,因为它们没有包裹在Route 中。

有人建议抓取所有布局的内容并将它们作为兄弟姐妹添加到当前路由中。然而,这对我来说是一团糟。我确实想将所有布局保存在单独的文件中,并且只将屏幕作为子项传递给它们。

【问题讨论】:

  • 你想在这里完成什么?您似乎只是想通过代码中的某种关系对路线进行分组。您是否尝试过在某些路线上使用exact,以免获得多个匹配项?
  • 其实,我明白你在这里的目的。我可能会建议将您的布局组件转换为处理布局的 HOC,并将您的路由“组件”作为参数并在正确的布局包装器中返回该组件,即&lt;Route path="/index" component={BaseLayout(Index)} /&gt;
  • @DrewReese,主要思想是防止当我从一个页面转到另一个页面时,重新呈现以相同布局包装的屏幕的共享元素(例如页眉、页脚)。如果我没记错的话,使用 HOC 无论如何都会重新渲染它们?
  • 我不确定我是否遵循,但每条路线都会独立于其他路线呈现。如果您有不同的页眉/页脚,这就是全部不同,那么您也可以直接在它们自己的路由上渲染它们,作为多个路由并渲染多个组件。我正在为我的公司构建的应用程序有一个页眉组件和页脚组件,它们在内部具有路由器,以便在不同路由上返回不同的组件,与内容区域中路由器中的匹配项分开。
  • @DrewReese,每个布局都有其独特的网格、元素等。我不能真正为布局内的每个网格元素使用路线。所以我只想将这些屏幕作为子元素传递,并且只在我从一个页面转到另一个页面时更新它们。

标签: javascript reactjs react-router react-router-dom


【解决方案1】:

这是一个潜在布局结构的粗略草图:

<Header>
  <Router>
    <Router path={['/index', '/about']} component={HeaderComponent} />
    <Router path={['/sign-in', '/sign-up']} component={AuthHeaderComponent} />
  </Router>
</Header>
<Screens>
  <Router>
    <Route path="/index" component={BaseLayout(Index)} />
    <Route path="/about" component={BaseLayout(About)} />
    <Route path="/sign-in" component={AuthLayout(SignIn)} />
    <Route path="/sign-up" component={AuthLayout(SignUp)} />
    <Route path="/stats" component={DashboardLayout(Stats)} />
  </Router>
</Screens>
<Footer>
  <FooterComponent />
</Footer>

在此示例中,包装器是 HOC,因此它们可以处理将所有道具从路由向下传递到页面组件,但如果您只想做一个内联包装器,您可以使用 render 函数:

<Route
  path="/index"
  render={routeProps => {
    return (
      <BaseLayout>
        <Index {...routeProps}/>
      </BaseLayout>
    );
  }}
/>

[编辑] 一个示例布局 HOC (docs)

const withBaseLayout = WrappedComponent => {
  // any business logic required for the layout
  // layoutProps, style, etc...
  return (
    <BaseLayout {...layoutProps}>
      <WrappedComponent {...this.props} /> // these are all the passed in props
      // you can inject more props into Wrapped component as well
      // i.e. redux's connect or react-router-dom's withRouter HOCs
    </BaseLayout>
  );
}

// in index.js
export default withBaseLayout(Index);

// in route
<Route path="/index" component={Index} /> // already wrapped

或者直接作为组件

const BaseLayoutHOC = WrappedComponent => {
  // any business logic required for the layout
  // layoutProps, style, etc...
  return (
    <BaseLayout {...layoutProps}>
      <WrappedComponent {...this.props} />
    </BaseLayout>
  );
}

// in route
<Route path="/index" component={BaseLayoutHOC(Index)} />

【讨论】:

  • 感谢您将其发布为 aswer。你介意分享一下BaseLayout(Index) HOC 的样子吗?
  • @sdvnksv 添加了一些简单的 HOC 和使用示例。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-02-18
  • 2016-11-12
  • 1970-01-01
  • 1970-01-01
  • 2020-01-04
  • 1970-01-01
相关资源
最近更新 更多