Raect 异步加载组件

发布于 2022-10-20 20:09:53 字数 3263 浏览 145 评论 0

首先需要知道的是 dynamic import 通过返回 Promise 的方式实现异步加载功能。

import('./component.js')  
    .then((m) => {
        // 处理异步加载到的模块m
    })
    .catch((err) => {
        // 错误处理
    });

要注意的是 import 的参数不能使用变量,简单原则是至少要让 Webpack 知晓应该预先加载哪些内容。这里的参数除了使用常量之外,还可以使用模板字符串 componentDir/${name}.js

其实到这里基本完成代码切割了,接下来做得就是结合 react-router 实现按模块异步加载。这是跟业务代码相关的,因此每个人的做法都是不一样的。所以以下代码仅供参考。

异步加载

我参考 react-router 的例子写了个简单的异步加载组件 AsyncLoader.js,内容:

import React from 'react';

export default class AsyncLoader extends React.Component {

  static propTypes = {
    path: React.PropTypes.string.isRequired,
    loading: React.PropTypes.element,
  };

  static defaultProps = {
    path: '',
    loading: <p>Loading...</p>,
    error: <p>Error</p>
  };

  constructor(props) {
    super(props);
    this.state = {
      module: null
    };
  }

  componentWillMount() {
    this.load(this.props);
  }

  componentWillReceiveProps(nextProps) {
    if (nextProps.path !== this.props.path
      || nextProps.error !== this.props.error
      || nextProps.loading !== this.props.loading) {
      this.load(nextProps);
    }
  }

  load(props) {

    this.setState({module: props.loading});

    // TODO:异步代码的路径希望做成可以配置的方式
    import(`./path/${props.path}`)
      .then((m) => {
        let Module = m.default ? m.default : m;
        console.log("module: ", Module);
        this.setState({module: <Module/>});
      }).catch(() => {
        this.setState({module: props.error});
      });
  }

  render() {
    return this.state.module;
  }
}

使用方法

<Route  
    exact path='/book' 
    render={()=><AsyncLoader path={'./components/Book.js'}/>} 
/>

Webpack 打包的时候会根据 import 的参数生成相应的 js 文件,默认使用 id(webpack 生成的,从 0 开始)命名这个文件。

const Search = asyncComponent(() => import(/* webpackChunkName: "search" */ "./containers/Search/SearchContainer"))
const BookList = asyncComponent(() => import(/* webpackChunkName: "bookList" */ "./containers/BookList/BookListContainer"))


import React from 'react'
export const asyncComponent = loadComponent => (
    class AsyncComponent extends React.Component {
        state = {
            Component: null,
        }

        componentWillMount() {
            if (this.hasLoadedComponent()) {
                return;
            }

            loadComponent()
                .then(module => module.default) ////兼容 module.default ? module.default : module
                .then((Component) => {
                    this.setState({ Component });
                })
                .catch((err) => {
                    console.error(`Cannot load component in <AsyncComponent />`);
                    throw err;
                });
        }

        hasLoadedComponent() {
            return this.state.Component !== null;
        }

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

灯角

暂无简介

0 文章
0 评论
23 人气
更多

推荐作者

missyouangeled

文章 0 评论 0

三生一梦

文章 0 评论 0

压抑⊿情绪

文章 0 评论 0

☆獨立☆

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文