React router 4嵌套路由替代技术

时间:2017-05-31 16:21:01

标签: javascript reactjs redux react-router react-router-v4

在尝试执行嵌套路由时,当路由通过Link或history.push更改时,我无法装入子组件;但如果直接在root.js文件中声明路由,它就可以工作。所以,理想情况下我想在root / routes.js文件中保留尽可能多的路由配置,而不是整个App(我正在迭代root / routes.js对象而不是自动执行此操作;我的意思是......尝试)

To break it down logically (it's a bit abstract, but check the code below afterwards please):
- There's a `root/routes.js` that has all the routes configuration (parents, nested components, etc)
- The `root.js` defines the `<Route...>` where the attribute `component` is the return value of a function that passes the `routes` configuration to its `routes` component prop
- the main wrapper iterates over the component prop `routes` and defines `child` routes automatically...I mean...I'm trying...

为什么我要这样做?我的大脑工作的方式,为什么不工作?反应路由器4之前是可能的

<MyAppWrapper>
 <CommonNavigationBar />
 <Main>
  ----- dynamic / changes by route etc -----
 </Main>
 <Footer />
</MyAppWrapper>

我想知道我的尝试失败了吗?

// Working version
import React from 'react'
import { Route } from 'react-router'
import { BrowserRouter } from 'react-router-dom'
import { Provider } from 'react-redux'
import rootRoutes from './routes'
import App from '../app/containers/app'

const Root = ({store, history}) => {
  return (
    <Provider store={store}>
      <BrowserRouter history={history}>
        <Route path='/' component={App} />
      </BrowserRouter>
    </Provider>
  )
}

export default Root

对于前面的示例,App组件是嵌套的,下面我正在尝试动态地执行此操作...并且由于某种原因它失败了!虽然它应该完全相同......某处必须有一个错字...

import React, { Component } from 'react'
import { isBrowser } from 'reactatouille'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import { withRouter, Route } from 'react-router'
import Navbar from '../navbar'
import JourneySelector from '../journeySelector'
import reservationFinder from '../../../reservationFinder'

// include the stylesheet entry-point
isBrowser() && require('../../../../sass/app.scss')

class App extends Component {
  constructor (props) {
    super(props)
    this.state = {
      init: true
    }
  }

  render () {
    return (
      <div className={'app' + ' ' + (!this.state.init && 'uninitialised')}>
        <Navbar />
        <main>
          <Route exact path='/' component={JourneySelector} />
          <Route exact path='/reservation-finder' component={reservationFinder.containers.App} />
        </main>
      </div>
    )
  }
}

// export default App
function mapStateToProps (state, ownProps) {
  return {
    // example: state.example
  }
}

function matchDispatchToProps (dispatch) {
  return bindActionCreators({
    // replay: replay
  }, dispatch)
}

export default connect(mapStateToProps, matchDispatchToProps)(withRouter(App))

虽然我的技术失败了(我所要做的就是迭代root / routes子路由来生成这些):

// root/routes.js
import app from '../app'
import reservationFinder from '../reservationFinder'

const rootRoutes = [
  {
    path: '/',
    component: app.containers.App,
    exact: true,
    routes: [{
      path: '/',
      exact: true,
      component: app.containers.JourneySelector
    }, {
      path: '/reservation-finder',
      component: reservationFinder.containers.App
    }]
  }
]

export default rootRoutes

根js文件。您看到setRoute fn返回一个新组件,其中子路由作为props传递?我相信这会奏效:

// root.js
import React from 'react'
import { Route, Switch } from 'react-router'
import { BrowserRouter } from 'react-router-dom'
import { Provider } from 'react-redux'
import rootRoutes from './routes'

const setRoute = (route) => {
  const MyComponent = route.component
  return <Route key={route.path} exact={route.exact || false} component={() => (<MyComponent routes={route.routes} />)} />
}

const Root = ({store, history}) => {
  return (
    <Provider store={store}>
      <BrowserRouter history={history}>
        { rootRoutes.map(route => setRoute(route)) }
      </BrowserRouter>
    </Provider>
  )
}

export default Root

我想用作包装器的主应用程序:

// main app 
import React, { Component } from 'react'
import { isBrowser } from 'reactatouille'
import { connect } from 'react-redux'
import { bindActionCreators } from 'redux'
import { withRouter, Route } from 'react-router'
import Navbar from '../navbar'

// include the stylesheet entry-point
isBrowser() && require('../../../../sass/app.scss')

class App extends Component {
  constructor (props) {
    super(props)
    this.state = {
      init: true
    }
  }

  render () {
    return (
      <div className={'app' + ' ' + (!this.state.init && 'uninitialised')}>
        <Navbar />
        <main>
          { Array.isArray(this.props.routes) && this.props.routes.map(route => <Route key={route.path} {...route} />) }
        </main>
      </div>
    )
  }
}

// export default App
function mapStateToProps (state, ownProps) {
  return {
    // example: state.example
  }
}

function matchDispatchToProps (dispatch) {
  return bindActionCreators({
    // replay: replay
  }, dispatch)
}

export default connect(mapStateToProps, matchDispatchToProps)(withRouter(App))

我明白我可能会有类似的东西,比如?!

// root
import React from 'react'
import { Route, Switch } from 'react-router'
import { BrowserRouter } from 'react-router-dom'
import { Provider } from 'react-redux'
import rootRoutes from './routes'
import MyAppWrapper from 'xxx/MyAppWrapper'    

const setRoute = (route) => {
  const MyComponent = route.component
  return <Route key={route.path} exact={route.exact || false} component={() => (<MyComponent routes={route.routes} />)} />
}

const Root = ({store, history}) => {
  return (
    <Provider store={store}>
      <BrowserRouter history={history}>
        <MyAppWrapper>
          <Route path='x' component={x} />
          <Route path='y' component={y} />
        </MyAppWrapper>
      </BrowserRouter>
    </Provider>
  )
}

export default Root

注意:在测试期间,我注意到它在服务器端工作?我的意思是,我可能错过了一些东西,而且我没有保存我的工作。此外,失败时,前一个组件(默认)仍然已安装且未卸载

我甚至尝试过(没有成功......我想知道这是不是一个错误):

import React from 'react'
import { Route } from 'react-router'
import { BrowserRouter } from 'react-router-dom'
import { Provider } from 'react-redux'
import App from '../app/containers/app'
import rootRoutes from './routes'

const Root = ({store, history}) => {
  return (
    <Provider store={store}>
      <BrowserRouter history={history}>
        <Route path='/' render={() => (
          <App />
        )} />
      </BrowserRouter>
    </Provider>
  )
}

export default Root

好的,我认为这是一个如此报告的错误(https://github.com/ReactTraining/react-router/issues/5190),您可以在此处找到实时示例(https://codepen.io/helderoliveira/pen/rmXdgd),点击topic。也许我正在尝试做的事情不受支持,但我们应该收到错误消息而不是空白。

1 个答案:

答案 0 :(得分:1)

好的,我发现了错字。解决方案是使用render并通过Object.assign和spread运算符传递routerProps +你想要的任何其他道具!

// root.js
import React from 'react'
import { Route } from 'react-router'
import { BrowserRouter } from 'react-router-dom'
import { Provider } from 'react-redux'
import App from '../app/containers/app'
import rootRoutes from './routes'

const Root = ({store, history}) => {
  return (
    <Provider store={store}>
      <BrowserRouter history={history}>
        <Route path='/' render={routeProps => <App {...Object.assign({}, routeProps, { routes: rootRoutes[0].routes })} />} />
      </BrowserRouter>
    </Provider>
  )
}

export default Root

主app包装器:

class App extends Component {
  render () {
    return (
      <div className={'app kiosk' + ' ' + (!this.state.init && 'uninitialised')}>
        <Navbar />
        <main>
          { Array.isArray(this.props.routes) && this.props.routes.map(route => <Route key={route.path} exact={route.exact} path={route.path} component={route.component} />) }
        </main>
      </div>
    )
  }
}   

export default App

路线档案:

import React from 'react'
import { Route } from 'react-router'
import { BrowserRouter } from 'react-router-dom'
import { Provider } from 'react-redux'
import rootRoutes from './routes'

const setRoute = (route) => {
  const MyComponent = route.component
  return <Route key={route.path} path={route.path} render={routeProps => <MyComponent {...Object.assign({}, routeProps, { routes: rootRoutes[0].routes })} />} />
}

const Root = ({store, history}) => {
  return (
    <Provider store={store}>
      <BrowserRouter history={history}>
        <div>
          { rootRoutes.map(route => setRoute(route)) }
        </div>
      </BrowserRouter>
    </Provider>
  )
}

export default Root