Umi: Support nested router

Created on 7 Feb 2018  ·  4Comments  ·  Source: umijs/umi

Most helpful comment

@sorrycc 云谦

我今天发现配置了page.js后,别的路由就不生成了,然后找到了这里,建议把下面这段话放到官方的文档里面。也是一种约定

注意:

不要用 page.js,因为用了 page.js 就不会往下找了
有 page.js 时同级目录下 _layout.js 不生效,因为没有必要
用 umi-plugin-routes 忽略一些不需要作为路由的文件,比如 models/**/*.js
有 layout 时会嵌套一层,没有则拍平

All 4 comments

方案

约定式路由的嵌套方案

目录结构,

+ pages
  - a.js
  + list
    - index.js
    - b.js
    - _layout.js

转化为以下 routesConfig,

[
  { path: '/a', exact: true component: './pages/a' },
  { path: '/list', exact: false, component: './pages/list/_layout',
    routes: [
      { path: '/list', exact: true, component: './pages/list/index' },
      { path: '/list/b', exact: true, component: './pages/list/b' },
    ],
  },
]

注意:

  1. 不要用 page.js,因为用了 page.js 就不会往下找了
  2. 有 page.js 时同级目录下 _layout.js 不生效,因为没有必要
  3. 用 umi-plugin-routes 忽略一些不需要作为路由的文件,比如 models/**/*.js
  4. 有 layout 时会嵌套一层,没有则拍平

把有嵌套规则的 routesConfig 渲染到页面上

e.g. routesConfig

[
  { path: '/', exact: true, component }
  { path: '/list', component,
    routes: [
      { path: '/list', exact: true, component },
      { path: '/list/$id', exact: true, component },
    ],
  }
]

由于 react-router-config 必须有 root 节点,所有需要套一层 layout。layouts/index.js 存在时用它,不存在时用一个假的。转换为:

[
  component: './layouts/index.js',
  routes: [/* OLD_ROUTES */]
]

由于需要处理按需编译和按需加载,所以得把 routesConfig 输出到页面上,便于输出不同的 Component 路径,(实现上用字符串注释配置数据占位,然后用 JSON.stringify 转成 JSON,再用 String.prototype.replace 替换应该会简单些,原来 JSON.stringify 可以传 replacer function)

const routes = [
  {
    component: 'require("./xxxxxx")',
    routes: [...]
  }
];

通过定制的 renderRoutes 函数渲染到页面,react-router-config 的 renderRoutes 不支持 props.children 方式。

function renderRoutes(routes, extraProps = {}, switchProps = {}) {
  return routes ? (
    <Switch {...switchProps}>
      {
        routes.map((route, i) => {
          return <Route
            key={route.key || i}
            path={route.path}
            exact={route.exact}
            strict={route.strict}
            render={props => {
              return (
                <route.component {...props} {...extraProps} route={route}>
                  { renderRoutes(route.routes) }
                </route.component>
              );
            }}
          />;
        })
      }
    </Switch>
  ) : null;
}

router.js 内容大致如下:

import dynamic from 'umi/dynamic';
import renderRoutes from 'umi/_renderRoutes';

const routes = [
  component: 'main layout',
  routes: [
    {
      path, exact,
      component: '<%= COMPILING %>^^route=<%= path %>',
      component: 'path/to/component/file',
      component: require('path/to/component/file').default,
      component: dynamic(() => import(/**/'path/to/component/file')),
      component: dynamic(() => import(/**/'path/to/component/file'), { loading }),
    },
  ],
];

export default () => {
  return (<Router history={window.g_history}>{ renderRoutes(routes) }</Router>);
};

react-router-config 可能有不支持动态加载的问题

动态加载在外面处理了,react-router-config/renderRoutes 也没有直接用,改写了一个版本。

@sorrycc 云谦

我今天发现配置了page.js后,别的路由就不生成了,然后找到了这里,建议把下面这段话放到官方的文档里面。也是一种约定

注意:

不要用 page.js,因为用了 page.js 就不会往下找了
有 page.js 时同级目录下 _layout.js 不生效,因为没有必要
用 umi-plugin-routes 忽略一些不需要作为路由的文件,比如 models/**/*.js
有 layout 时会嵌套一层,没有则拍平
Was this page helpful?
0 / 5 - 0 ratings

Related issues

ddzy picture ddzy  ·  3Comments

nguyenhuutinh picture nguyenhuutinh  ·  3Comments

miaojinxing picture miaojinxing  ·  3Comments

six-666 picture six-666  ·  3Comments

y2891663091 picture y2891663091  ·  4Comments