# React路由组件按需异步加载实践

版本信息:当前使用React版本16.13.1

# 一、路由的配置

一般来说,我们在React中写路由的时候都是这样:👇







 




// 多余代码省略...
import MainPage from "./pages/mainPage";

...
<Switch>
  ...
  <Route strict exact path="/mianpage" component={MainPage} />
  ...
</Switch>
...
1
2
3
4
5
6
7
8
9
10

但实际上这种写法只适合简单且没几个页面的场景。对于大型项目或者一款产品,路由写死/固定肯定不行(这样维护比较麻烦),它们的路由肯定是动态的、可配置的

# 二、尝试配置动态路由

# 1.使用() => import(componentPath)

用过Vue的同学都知道,在Vue-Router中可以使用component: () => import("./pages/mainPage")来给路由添加组件。那么React中也是这样❓

// 多余代码省略...
<Switch>
  ...
  <Route
    strict
    exact
    path="/mianpage"
    component={() => import("./pages/mainPage")}
  />
  ...
</Switch>
1
2
3
4
5
6
7
8
9
10
11

# 2.结果报了一堆错误,尝试失败

async-router-01

Uncaught Error: Objects are not valid as a React child (found: [object Promise])...

错误翻译过来就是返回的是promise对象。。

# 三、使用中间件异步加载组件

前一节中的错误是因为使用import返回的是一个promise对象,显然不能作为组件使用。

此时需要一个中间件对其进行处理并返回一个组件

展开查看代码
// AsyncComponent.jsx
import React from "react";

// 将普通组件转换为动态组件
const AsyncComponent = (loadComponent, _props) => {
  return class extends React.Component {
    constructor(props) {
      super(props);

      this.state = {
        Component: null
      };
    }

    componentDidMount() {
      if (this.state.Component !== null) return;

      loadComponent()
        .then(module => module.default)
        .then((component) => {
          this.setState({Component: component});
        })
        .catch((err) => {
          throw err;
        });
    }

    render() {
      const { Component } = this.state;
      return (Component) ? <Component {...this.props} {..._props} /> : null;
    }
  };
};

export default AsyncComponent;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35

# 使用示例

// router 多余代码省略...
import { AsyncComponent } from "./utils/AsyncComponent";

<Switch>
  ...
  <Route
    strict
    exact
    path="/mianpage"
    component={AsyncComponent(() => import("./pages/mainPage"), {somePropsData})}
  />
  ...
</Switch>
1
2
3
4
5
6
7
8
9
10
11
12
13

# 四、参考资料

Last Updated: 2 years ago