title:
order: 4

category: ICE Design Pro

路由配置

在模板中,路由与菜单一样也是按照一定的约定进行配置,用来描述路由的结构关系。路由主要分为 路由配置 和 路由生成 两部分:

  • 路由配置:在 src/routerConfig.js 中配置路由
  • 路由生成:在 src/router.js 中生成路由

这样设计的目的主要是分离路由配置信息和路由生成部分,配置和生成进行解耦,有利于在新增路由时只需要关注路由配置,除了顶层路由,其余路由列表都是自动生成,其中关键的就是中心化配置文件 src/routerConfig.js,它的主要作用是:

  • 配置路由相关信息,可以配置对应路由的路径,渲染组件,权限,布局等字段;
  • 根据路由配置生成路由数据,并将路由数据挂载到每条路由对应的组件上;
  1. const routesConfig = [
  2. {
  3. path: '/post',
  4. layout: BasicLayout,
  5. component: PostList,
  6. children: [
  7. {
  8. path: 'list', // 路径
  9. layout: BasicLayout, // 布局
  10. component: PostList, // 组件
  11. authority: 'user', // 权限
  12. },
  13. {
  14. path: 'create',
  15. layout: BasicLayout,
  16. component: CreatePost,
  17. authority: 'admin',
  18. },
  19. ],
  20. },
  21. ];

路由生成

基础知识

模板中使用的是 React Router v4 版本,相较于 React Router 前面三个版本发生了较大的改变,在写法以及 API 上也完全不同;我们来对比一下 v3 和 v4 的写法:

在 v3 之前的版本,通常的做法是将路由规则集中化在一个位置进行配置,使他们与布局以及组件进行分离。当然,你也可以将路由划分成多个文件进行管理,但本质上都是以路由单元进行文件配置化,看一个简单的示例,包含首页和用户页面的路由配置:

  1. // 代码来源:https://css-tricks.com/react-router-4/
  2. import { Router, Route, IndexRoute } from 'react-router';
  3. const PrimaryLayout = (props) => (
  4. <div className="primary-layout">
  5. <header>Our React Router 3 App</header>
  6. <main>{props.children}</main>
  7. </div>
  8. );
  9. const HomePage = () => <div>Home Page</div>;
  10. const UsersPage = () => <div>Users Page</div>;
  11. const App = () => (
  12. <Router history={browserHistory}>
  13. <Route path="/" component={PrimaryLayout}>
  14. {' '}
  15. // Layout 配置
  16. <IndexRoute component={HomePage} /> // 首页
  17. <Route path="/users" component={UsersPage} /> // 用户页面
  18. </Route>
  19. </Router>
  20. );
  21. render(<App />, document.getElementById('root'));

而在 v4 中不再提倡中心化的路由管理,推荐路由规则位于布局和 UI 组件本身。对比上面 v3 的路由,以下是在 v4 中的实现:

  1. // 代码来源:https://css-tricks.com/react-router-4/
  2. import { BrowserRouter, Route } from 'react-router-dom';
  3. const PrimaryLayout = () => (
  4. <div className="primary-layout">
  5. <header>Our React Router 4 App</header>
  6. <main>
  7. <Route path="/" exact component={HomePage} /> // 路由配置在这里
  8. <Route path="/users" component={UsersPage} />
  9. </main>
  10. </div>
  11. );
  12. const HomePage = () => <div>Home Page</div>;
  13. const UsersPage = () => <div>Users Page</div>;
  14. const App = () => (
  15. <BrowserRouter>
  16. <PrimaryLayout />
  17. </BrowserRouter>
  18. );
  19. render(<App />, document.getElementById('root'));

对比上面的两种实现,我们可以看到,在 v4 中路由处于 PrimaryLayout 之中,并不是通过 props.children 来嵌套组件渲染,而是 <Route> 组件分布式的在各个组件自身,如果路由匹配,则子组件就在对应的位置渲染。

如果你还不太了解,可以先看看下面几篇推荐的文章:

具体使用

接下来具体看看在模板中我们是如何来实现的;基于路由配置,可以发现每个对应的路由都可以配置一个单独的布局,可以是相同的也可以是不相同的布局,在这种情况下,意味着每个路由入口都包含了一个新的布局,实现如下:

  • 主路由入口:
  1. import { routerData } from './routerConfig';
  2. const router = () => {
  3. return (
  4. <Switch>
  5. {routerData.map((item, index) => {
  6. return <Route key={index} path={item.path} component={item.layout} />;
  7. })}
  8. <Redirect exact from="/" to="/dashboard" />
  9. </Switch>
  10. );
  11. };
  • 对应的布局中的路由实现
  1. // BasicLayout.jsx
  2. ...
  3. <Layout.Main>
  4. <Switch>
  5. {routerData.map((item, index) => {
  6. return item.component ? (
  7. <Route
  8. key={index}
  9. path={item.path}
  10. component={item.component}
  11. exact={item.exact}
  12. />
  13. ) : null;
  14. })}
  15. </Switch>
  16. <Layout.Main>
  17. ...

这样我们将路由分成了两部分,一部分在主路由入口,主要控制布局的渲染;其次在布局中,通过 <Route> 组件渲染当前布局对应的组件。但这样设计有个缺点,因为考虑到每个路由都可以支持不同的布局,实际上会导致在每次进入页面都会重新加载,要解决这个问题,可以通过自定义修改路由来避免。

自定义修改路由

在实际项目中,可能你并没有为每个路由创建不同布局的需求,通常来讲可能只会有用户登录布局 (UserLayout) 和完成登录后进入主界面的基础布局(BasicLayout),如果是这样,我们建议你对路由做一次修改,避免每次进入页面都会重新加载布局的问题,修改方式如下:

  • 修改 routerConfig.js 的配置如下:
  1. const routerConfig = [
  2. {
  3. path: '/',
  4. component: BasicLayout, // 主页面布局
  5. },
  6. {
  7. path: '/list/article-list',
  8. component: List,
  9. },
  10. {
  11. path: '/list/card-list',
  12. component: CardList,
  13. }
  14. {
  15. path: '/user',
  16. component: UserLayout, // 用户登录注册页布局
  17. },
  18. {
  19. path: '/user/login',
  20. component: UserLogin,
  21. },
  22. {
  23. path: '/user/register',
  24. component: UserRegister,
  25. },
  26. ];
  • 修改 router.js 的配置如下:
  1. const router = () => {
  2. return (
  3. <Switch>
  4. <Route path="/user" component={UserLayout} /> // 用户登录注册页布局
  5. <Route path="/" component={BasicLayout} /> // 主页面布局
  6. </Switch>
  7. );
  8. };

修改之后的路由配置主要是对路由按照布局进行了分组,然后在布局中渲染对应的路由,而不是为每个路由指定一个布局。通过修改,你也可以很容易的添加其他的布局,如添加一个 NormalLayout 如下:

  1. // in routerConfig.js
  2. const routerConfig = [
  3. ...
  4. {
  5. path: '/',
  6. component: BasicLayout,
  7. },
  8. {
  9. path: '/user',
  10. component: UserLayout,
  11. },
  12. {
  13. path: '/noraml',
  14. component: NoramlLayout,
  15. },
  16. ...
  17. ]
  18. // in router.js
  19. <Switch>
  20. <Route path="/user" component={UserLayout} />
  21. <Route path="/noraml" component={UserLayout} />
  22. <Route path="/" component={BasicLayout} />
  23. </Switch>

至此,模板中的路由设计方案基本分析完成,这里可以总结如下:

  • 考虑到每个路由都能配置任意不同的布局,在渲染的时候实际上是每个路由都会渲染对应的布局,但即使是同一个布局也会导致重新渲染。
  • 如果您的实际项目没有多布局的需求,建议通过自定义修改路由的方式进行处理,避免重复的渲染操作。