Dva: react-router@v4的路由嵌套model注册问题

Created on 24 Sep 2017  ·  12Comments  ·  Source: dvajs/dva

当各个子路由页面有公用代码部分,这部分公共代码会提出来放在父路由中,在dva@2中由于使用了react-router@4,子路由只能放在父路由页面内,于是就会出现下面这种路由组织:

// 最外层父路由
......
export default ({ history, app }) => {
  const App = dynamic({
    app,
    models: () => [appModel],
    component: () => import('./routes/App'),
  });

  return (
    <Router history={history}>
      <Switch>
        <Route path="/" component={App} />
      </Switch>
    </Router>
  );
};
// 父页面内容示例
......
import Item from '../Item';

class App extends Component {
  render() {
    return (
      <div className="app-wrap">
        <Link to="/id">go to id</Link>
        <Switch>
          <Route path="/id" component={Item} />
        </Switch>
      </div>
    );
  }
}

const mapStateToProps = state => ({
  appState: state.app
});

export default connect(mapStateToProps)(App);

那么在App这个页面中怎么去注册Item页面的model呢?

Most helpful comment

同样的问题,后来看了下官方的这个文档,
https://reacttraining.com/react-router/web/example/route-config

// wrap and use this everywhere instead, then when
// sub routes are added to any route it'll work
const RouteWithSubRoutes = (route) => (
// pass the sub-routes down to keep nesting

)}/>
)

重点在子路由在父路由的 render 里嵌套生成。

All 12 comments

用 context 往下传 app ?

那样的话,把公用部分提取出来为一个组件,在每个页面中引入,在路由页面统一注册model,这样的实践方式更好吧?

可能这样的写法更好,这样我就可以在router.js中一起完成model的注册了:

export default ({ history, app }) => {
  const App = dynamic({
    app,
    models: () => [appModel],
    component: () => import('./routes/App'),
  });

  const Item = dynamic({
    app,
    models: () => [appModel],
    component: () => import('./routes/Item'),
  });

  const OtherItem = dynamic({
    app,
    models: () => [appModel],
    component: () => import('./routes/Other'),
  });

  return (
    <Router history={history}>
      <div>
        <App />
        <Switch>
          <Route path="/id" component={Item} />
          <Route path="/otherid" component={OtherItem} />
        </Switch>
      </div>
    </Router>
  );
};

App页面中也不需要创建新的子路由,无论子页面如何变动都会展示App页面中的内容。
虽然这样会有一个问题就是从DOM结构上,子路由并不是包裹在父元素内部的。。。

同样的问题,后来看了下官方的这个文档,
https://reacttraining.com/react-router/web/example/route-config

// wrap and use this everywhere instead, then when
// sub routes are added to any route it'll work
const RouteWithSubRoutes = (route) => (
// pass the sub-routes down to keep nesting

)}/>
)

重点在子路由在父路由的 render 里嵌套生成。

@kobelin923 嗯,这个问题我已经转换思路解决了,我还是选择把路由都配置在了同一个页面内,对model的注册不会有影响,对页面结构也一样。

export default ({ history, app }) => {
  const App = dynamic({
    app,
    models: () => [appModel],
    component: () => import('./routes/App'),
  });

  const Item = dynamic({
    app,
    models: () => [appModel],
    component: () => import('./routes/Item'),
  });

  const OtherItem = dynamic({
    app,
    models: () => [appModel],
    component: () => import('./routes/OtherItem'),
  });

  return (
    <Router history={history}>
      <div className="root-wrap">

        {/* 菜单栏 */}
        <nav className="aside">
          <Menu
            mode="inline"
          >
            <Menu.Item key="/">
              <Link to="/">首页</Link>
            </Menu.Item>
            <Menu.Item key="/id">
              <Link to="/id">子页面</Link>
            </Menu.Item>
            <Menu.Item key="/otherid">
              <Link to="/otherid">另一个子页面</Link>
            </Menu.Item>
          </Menu>
        </nav>

        <div className="main-content">

          {/* 公共部分 */}
          <App />

          {/* 路由 */}
          <Switch>
            <Route exact path="/" render={() => (<div>这里会显示各个路由的内容</div>)} />
            <Route path="/id" component={Item} />
            <Route path="/otherid" component={OtherItem} />
          </Switch>
        </div>
      </div>
    </Router>
  );
};

我写了个项目模版仅供参考:https://github.com/bingqichen/react-with-dva-template

这就结束了啊,题主遇到的问题只是简单的嵌套,把layout放到了router里面来绕过这个问题,但可有更好的通用点的解决方案?
@sorrycc 是你说的这样更通用么?"用 context 往下传 app ?"

感觉layout和路由混在一起并不是一个很好的解决方案。

@wuzhuzhu 就算你把子路由放在组件里面还是和layout组合在一起的,react-router@v4的设计思想也是将Route作为普通React组件看待,让React Router在React的大框架下运转。

我是这样写的:

import React from 'react'
import modelExtend from 'dva-model-extend'
import { Route, Switch, Redirect } from 'react-router-dom'
import dynamic from 'dva/dynamic'

import app from '../../../index' // 从 /src/index.js 导入的app
import ClassBasicModel from './ClassMaintenance/basicModel'

function StepRoutes({ match }) {
  const id = match.params.id
  const routes = [{
    path: `${match.url}/class-maintenance`,
    models: () => [modelExtend(ClassBasicModel, { namespace: `class-maintenance-${id}` })],
    component: () => import('./ClassMaintenance'),
  }, {
    path: `${match.url}/course-selection`,
    models: () => [import('./CourseSelection/basicModel')],
    component: () => import('../Steps/CourseSelection'),
  }, {
    path: `${match.url}/resource-arrangement`,
    component: () => import('../Steps/ResourceArrangement'),
  }, {
    path: `${match.url}/walking-class-arrangement`,
    component: () => import('../Steps/WalkingClassArrangement'),
  }]
  return (
    <Switch>
      <Route exact path={match.url} render={() => (<Redirect to={`${match.url}/class-maintenance`} />)} />
      {
        routes.map(({ path, ...dynamics }, index) => (
          <Route
            key={index}
            exact
            path={path}
            component={dynamic({ app, ...dynamics })}
          />
        ))
      }
    </Switch>
  )
}

export default StepRoutes

功能实现了, 但是会报错, 这是为什么 呢

warning.js?6327:33 Warning: Can only update a mounted or mounting component. This usually means you called setState, replaceState, or forceUpdate on an unmounted component. This is a no-op.

Please check the code for the DynamicComponent component.

@zmayor 我也报同样的错误,你解决了吗?

并没有, 再不行只能放弃动态加载了

Was this page helpful?
0 / 5 - 0 ratings

Related issues

MiaoXingGua picture MiaoXingGua  ·  3Comments

kpaxqin picture kpaxqin  ·  3Comments

pengfeiWang picture pengfeiWang  ·  3Comments

hanxiansen picture hanxiansen  ·  3Comments

mclouvem picture mclouvem  ·  4Comments