React Router v4 嵌套路由 props.children

Posted

技术标签:

【中文标题】React Router v4 嵌套路由 props.children【英文标题】:React Router v4 nested routes props.children 【发布时间】:2017-08-28 01:14:17 【问题描述】:

我正在更新我的通用 react redux 应用程序以使用 react router v4。我在主要布局路线下有嵌套路线。以前我使用 props.children 来显示子路由的内容,但这不再起作用了。这在 V4 中如何工作?

<Provider store=store key="provider">
  <div>
    <Route component=Layout />
    <Switch>
      <Route path="/" component=HomePage />
      <Route component=Error404 />
    </Switch>
  </div>
</Provider>

<Provider store=store key="provider">
  <Layout>
    <Route path="/" component=HomePage />
    <Route component=Error404 />
  </Layout>
</Provider>

这就是我的布局文件的样子

const Layout = props => (
 <div className="o-container">
   <Header />
     <main>
      props.children
     </main>
   <Footer />
 </div>
);

【问题讨论】:

【参考方案1】:

只是觉得我必须分享这个。如果您在 Header 组件中使用 Link 组件。上面的答案是行不通的。您必须再次将BrowserRouter 设为父级以支持Link。变成这样:

<BrowserRouter>
 <Layout>
  <Switch>
    <Route exact path="/" component=HomePage />
    <Route path="/other" component=OtherComponent />
    <Route component=Error404 />
  </Switch>
 </Layout>
</BrowserRouter>

【讨论】:

如果他们尝试这样做,这对于任何发现问题的人来说都是一个好点。 OP 起初只是想将路线加载为他的布局的子项。【参考方案2】:

请仔细阅读此博客。 https://codeburst.io/react-router-v4-unofficial-migration-guide-5a370b8905a

没有了&lt;IndexRoute&gt;

在 v3 中允许路由到***路径上的某个组件的组件:

// in src/MyApp.js
const MyApp = () => (
    <Router history=history>
        <Route path="/" component=Layout>
            <IndexRoute component=Dashboard />
            <Route path="/foo" component=Foo />
            <Route path="/bar" component=Bar />
        </Route>
    </Router>
)

这个组件在 v4 中不再存在。要替换它,请结合使用 、exact 和 route ordering(将索引路由放在最后):

  // in src/MyApp.js
const MyApp = () => 
    <Router history=history>
        <Route path="/" component=Layout />
    </Router>

// in src/Layout.js
const Layout = () => (
    <div className="body">
        <h1 className="title">MyApp</h1>
        <div className="content">
            <Switch>
                <Route exact path="/foo" component=Foo />
                <Route exact path="/bar" component=Bar />
                <Route exact path="/" component=Dashboard />
            </Switch>
        </div>
    </div>
);

【讨论】:

如果索引路由是精确的,那你为什么要把它放在最后呢? IMO 放在最后还是第一个都没关系。【参考方案3】:

我会使用这种结构,没有 props.children :

const Main = () => (
  <main>
    <Switch>
      <Route exact path="/" component=HomePage />
      <Route component=Error404 />
    </Switch>
  </main>
)

const Layout = () => (
  <div>
    <Header />
    <Main />
    <Footer />
  </div>
)

ReactDOM.render((
    <Provider store=store>
      <BrowserRouter>
        <Layout />
      </BrowserRouter>
   </Provider>
), document.getElementById('root'))

【讨论】:

【参考方案4】:

如果与 Redux 一起使用,则不带 Switch 元素

AppRouter.js

import React from 'react'
import  BrowserRouter as Router, Route, Link  from 'react-router-dom'



const AppRouter = () => (
  <Layout>
    <Router>
      <div>
        <nav>
          <ul>
            <li><Link to="/">Home</Link></li>
            <li><Link to="/about">About</Link></li>
            <li><Link to="/contact">Contact</Link></li>
          </ul>
        </nav>
        <Route exact path="/" component=Home/>
        <Route path="/about" component=About/>
        <Route path="/contact" component=Contact/>
      </div>
    </Router>
  </Layout>
)

export default AppRouter;

布局.js

const Layout = props => (
  render() 
    return (
      <div className="container">
        <Header />
        <main>props.children</main>
        <Footer />
      </div>
    );
  
);

export default Layout;

Provider 放置在 Render 函数中

import React from 'react';
import ReactDOM from 'react-dom';
import  Provider  from 'react-redux';
import  createStore, applyMiddleware  from 'redux';


import AppRouter from './AppRouter';
import reducers from './reducers';

const createStoreWithMiddleware = applyMiddleware()(createStore);

ReactDOM.render(
  <Provider store=createStoreWithMiddleware(reducers)>
    <AppRouter />
  </Provider>
  , document.getElementById('app'));

【讨论】:

【参考方案5】:

添加到@Dez 答案

完整的原生/核心实现,支持 Redux

index.js

import React from 'react';
import ReactDOM from 'react-dom';
import  Provider  from 'react-redux';
import  Router, Route, Switch  from 'react-router';
import createMemoryHistory from 'history/createMemoryHistory';

const history = createMemoryHistory();

import App from './components/App';
import Home from './components/Home';
import Login from './components/Login';
import store from './store';

ReactDOM.render((
  <Provider store= store >
    <Router history=history>
      <App>
        <Switch>
          <Route exact path="/" component=Home />
          <Route path="/login" component=Login />
        </Switch>
      </App>
    </Router>
  </Provider>
), document.getElementById('root'));

App.js

import Header from './Header';
import Home from './Home';
import React from 'react';
import connect from 'react-redux';

const mapStateToProps = state => (appName: state.appName);

class App extends React.Component 
  render() 
    return (
      <div >
        <Header appName=this.props.appName /> /*common header*/
        this.props.children
      </div>
    );
  


export default connect(mapStateToProps, () => ())(App);

【讨论】:

【参考方案6】:

我采用了&lt;Provider&gt;out,因为它属于react-redux,并且您不需要它作为使用react-router 进行路由的基础(无论如何您可以轻松地添加它来封装结构)。

在 React Router V4 中,Router 已重命名为 BrowserRouter 并从包 react-router-dom 中导入。因此,对于嵌套路由,您需要将其作为 &lt;Layout&gt; 的子级插入。

index.js

import  Switch, Route  from 'react-router';
import  BrowserRouter  from 'react-router-dom';
import Layout from './Layout';
...
const Root = () => (
  <Layout>
    <BrowserRouter>
      <Switch>
        <Route exact path="/" component=HomePage />
        <Route path="/other" component=OtherComponent />
        <Route component=Error404 />
      </Switch>
    </BrowserRouter>
  </Layout>
);

ReactDOM.render(
  <Root/>,
  document.getElementById('root')
);

布局.js

import React from 'react';
import Header from './Header';
import Footer from './Footer';

const Layout = props => (
  render() 
    return (
      <div className="o-container">
        <Header />
        <main>props.children</main>
        <Footer />
      </div>
    );
  
);

export default Layout;

考虑一下,这仅适用于网络。本机实现不同。 我在 Create React App 中上传了 a small project,我在其中展示了 V4 中嵌套路由的实现。

【讨论】:

感谢@Dez 的回复,我改变了我的结构。部分问题在于它是一个通用应用程序,所有路由都需要在 中,以及客户端的 中。当我包含来自 react-router-dom 的链接时,我仍然在服务器上收到错误 @blamb 正如在这个问题的答案***.com/a/44799564/305953 中所说,IndexRoute 在 React Router 4 中不再可用。您在此处有 RR4 文档:reacttraining.com/react-router/web/guides/philosophy跨度> @Dez 抱歉不得不删除评论来更新它,没有注意到你已经回答它被隐藏了。如果不使用父 div 并在 &lt;/BrowserRouter&gt; 内使用 &lt;Route path="/" component=Layout&gt;&lt;IndexRoute component=Home/&gt;,无论是否有包装 div,我都无法让子路由以旧方式工作。我想要加载一个布局,以及在给定路线的布局内加载的路线。关于这部分,我不清楚文档。有没有更多的文档?

以上是关于React Router v4 嵌套路由 props.children的主要内容,如果未能解决你的问题,请参考以下文章

React Router v4 中的嵌套路由

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

React-router-dom v4 嵌套路由不起作用

在 react-router v4 中嵌套路由

嵌套路由不使用React Router v4呈现

浅入浅出 react-router v4 实现嵌套路由