如何在React Router v4中嵌套路由?

21

在React Router v4中,是否有一种嵌套路由的方法?

这是可行的:

  <Router basename='/app'>
    <main>
      <Route path='/' component={AppBar} />
      <Route path='/customers' component={Customers} />
    </main>
  </Router>

这个不会:

  <Router basename='/app'>
    <Route path='/' component={AppBar}>
      <Route path='/customers' component={Customers} />
    </Route>
  </Router>

客户组件:

import React, { Component, PropTypes } from 'react'
import styled from 'styled-components'

export default class Customers extends Component {
  render () {
    return (
      <Container>
        <h1>Customers</h1>
      </Container>
    )
  }
}

const Container = styled.section`
  height: 100%;
  padding: 15px;
  overflow: auto;
`

@ExperimentsWithCode,我主要是想看看是否有一种方法可以避免需要一个包装器(即<main>),因为<Router>只能有一个子元素。 - Raphael Rafatpanah
在第二个例子中,“Customers”组件没有被渲染。 - Raphael Rafatpanah
你能发布你的客户组件吗? - ExperimentsWithCode
@ExperimentsWithCode,已发布。 - Raphael Rafatpanah
AppBar组件中是否有{children}标签? - ExperimentsWithCode
显示剩余2条评论
6个回答

37

目前为止我发现的最佳模式。

// main app
<div>
    // not setting a path prop, makes this always render
    <Route component={AppShell}/>
    <Switch>
        <Route exact path="/" component={Login}/>
        <Route path="/dashboard" component={AsyncDashboard(userAgent)}/>
        <Route component={NoMatch}/>
    </Switch>
</div>

我可以将这个组件嵌套在另一个组件中,这样一切都可以很好地工作,包括热更新(如果使用webpack,请不要忘记将output.publicPath设置为"/")。

// dashboard component
<div>
    // the same way as before, not setting a path prop
    // makes it render on every /dashboard/** request 
    <Route component={DashboardTAB}/>
    <Switch>
        // longer path (with same root) than others first
        <Route path="/dashboard/graphs/longerpath" component={GraphForm}/>
        <Route path="/dashboard/graphs" component={Graphs}/>
        <Route path="/dashboard/workers" component={List}/>
        <Route path="/dashboard/insert" component={InsertComponent}/>
    </Switch>
</div>

我是这样做的,但使用了一个主父布局,没有错误地运行,但在组件中只显示<switch>中的第一个路由,并且当我点击链接时没有页面更改。我也使用了webpack,并按照您所说的将output.publicPath放置在其中。还有其他问题吗?谢谢。 - pirs
1
完美的,没问题,我刚刚开始了第一条路线,使用最短路径,因此最短路径是唯一可用的。 - pirs
1
没有设置路径属性解决了我遇到的问题。谢谢! - NaN

8

我从文档中进行了修改,目前看起来可以正常工作。可能会漏掉一些显而易见的东西。是的,这不是v4的方式,但我们需要在一个地方定义所有的路由。

function RouteNest(props){ return (
  <Route exact={props.exact} path={props.path} render={ p => <props.component {...p} children={props.children}/> } />
)}

export const MainRoutes = props => 

<div className='content layout'>

  <Route exact path="/" component={Landing}/>
  <Route  path={'/contact'} component={Contact}/>

  <RouteNest  path={'/thing'} component={CompoWithSub}>
    <RouteNest  path={'/thing/suba'} component={SubComponentA}/>
    <RouteNest  path={'/thing/subb'} component={SubComponentB}/>
  </RouteNest>


</div>

export const CompoWithSub = props => <div>{props.children)</div>

1

如果有人想要嵌套路由而无需输入包装路由的前缀,我已经在TSX中创建了类似于以下内容:

导入:

import * as React from 'react';
import { Route, RouteComponentProps, RouteProps, Switch } from 'react-router-dom';
import Index from 'views/index';
import Login from 'views/login';
import NoMatch from 'views/no-match';

接口:

interface INestedRoutes {
    nested?: string;
}

interface INestedRoute extends RouteProps, INestedRoutes {}

NestedRoute 和 NestedRoutes 包装器:

class NestedRoutes extends React.Component<INestedRoutes> {
    public render() {
        const childrenWithProps = React.Children.map(this.props.children, (child) => {
            return React.cloneElement(
                child as React.ReactElement<any>, { nested: this.props.nested },
            );
        })
        return childrenWithProps;
    }
}


const NestedRoute: React.SFC<INestedRoute> = (props: INestedRoute) => {
    return <Route path={`${props.nested}${props.path}`} component={props.component} />;
};

带有包装器的路由:

const MultiLanguage: React.SFC<RouteComponentProps<any>> = (props: RouteComponentProps<any>) => {
    return (
        <NestedRoutes nested={props.match.path} >
            <NestedRoute path="/test" component={Login} />
            <NestedRoute path="/no-match" component={NoMatch} />
        </NestedRoutes>
    );
};


export default (
    <Switch>
        <Route path="/:language" component={MultiLanguage}/>
        <Route exact={true} path="/" component={Index} />
        <Route path="/login" component={Login} />
        <Route component={NoMatch} />
    </Switch>
);

1

您的AppBar组件负责呈现客户。要调用客户,必须呈现AppBar的子元素。直接嵌套在AppBar下方的任何内容都是AppBar的子元素。

import React from 'react';

const AppBar = ({ children }) => (
  <div>
    <header>
       <h1> stuff </h1>
    </header>
    {children}
  </div>
);

export default AppBar

请注意,仅当您访问“/”时,AppBar才会呈现。当您访问“/customers”时,AppBar和Customers都会呈现。

即使使用<AppBar />{ children }进行渲染,当嵌套在React Router v4中时,<Customers />组件仍不会被渲染。 - Raphael Rafatpanah
真糟糕。我以为我在v4上,但我在v3上。对此感到抱歉。不确定这两个版本之间有什么变化。 - ExperimentsWithCode
实际上还有另一个使用路由配置的示例:https://reacttraining.com/react-router/examples/route-config 但我宁愿不使用路由配置。 - Raphael Rafatpanah
@RaphaelRafatpanah如果您能够使用route-config示例使嵌套工作,请发布一些示例代码吗?我已尽可能地模仿它,但仍然无法在v4中正确呈现v3嵌套路由时获得的简单行为。 - capouch
@capouch,到目前为止还没有成功。我目前正在使用一个包装元素,但我对此并不满意。 - Raphael Rafatpanah
显示剩余3条评论

0

路由期望只有一个子组件,而不是一个新的路由。 你可以将嵌套路由包含在你的客户组件中。

同时确保在客户组件中删除路由中的exact属性。


0

对于嵌套路由,我使用了一种非常简单的方法。

例如,主路由器可能是这样的:

<Router history={history}>
  <Switch >
    <Route path="/" component={Home}></Route>
  </Switch>
</Router>

在 Home 组件中使用嵌套路由的样子就像:

<div className="App">
  <Navbar title="Home" links = { NavbarLinks }/>
  {this.renderContentPage()}
</div>

renderContentPage函数将检查URL并呈现嵌套路由。

<Route exact path="/" component={Page1}></Route>
<Route exact path="/page1" component={Page1}></Route>
<Route exact path='/page2' component={Page2} />

因此,在主页组件中,页面1和页面2组件被渲染。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接