[译]使用 Webpack 异步加载 ReactJS 组件

为了加快 ReactJS 应用的初始化加载速度,一种行之有效的办法就是避免在应用启动时加载大型的组件,而是在它们被使用时加载,即按需加载。

Webpack(如果你还没有使用它,可以尝试一下)是一种模块化加载打包工具,允许我们将应用分割成块(chunks)并在需要时由客户端去下载。

要在 ReactJS 应用中使用 Webpack 的这一个功能,我们需要找到一种方法将组件打包成块,然后以异步的方式加载它们。

打包组件成块

要定义一个新的(异步)块,使用 Webpack 提供的require.ensure()方法即可,而不是同步的require()方法,例如下面的代码(代码使用 ES6语法):

require.ensure([], () => {  
    require('pulpy/dist/styles/styles.scss');
    let pulpy = require('pulpy');
    // pulpy 现在由Webpack加载了
    // 我们可以同步使用它
});

require.ensure是webpack核心方法,它告诉 webpack什么时候静态地分析这个作用范围(该异步函数的),并请求从每个依赖中生成一个独立的块。

然后,当应用中该代码执行的时候,Webpack 自动下载相应的块并在下载结束时,执行指定的匿名方法并保证此方法内由require()引用的调用同步满足(通常是这样)。

固定 Webpack块

当在应用中多个接口中使用了相同的异步加载的组件,如果你多次定义require.ensure(),那么 Webpack就会生成多个块,则在多个不同块中组件会被下载多次,这不但浪费了用户的时间,同时也浪费了带宽。很明显,这不是我们希望看到的。

解决方案就是将加载对应组件的require.ensure()放置到一个 贯穿于应用中并多次调用的loader 函数中,保证每个组件只使用一次require.ensure(),结果就是每个组件生成一个块(好)。

这样做的话,我们可以将loader封装于一个Promise中,这样更容易在后面使用loader,例如:

// Components/Chunks/Pulpy.js
'use strict';

export default () => {  
    return new Promise(resolve => {
        require.ensure([], () => {
            require('pulpy/dist/styles/styles.scss');

            resolve({
                pulpy: require('pulpy')
            });
        });
    });
};

应用中使用异步加载的组件

现在我们知道如何以异步的方式加载组件,那么如何在应用中使用它们?

我们简单地利用 ReactJS 组件的惊人的交互优势,通过在componentWillMount()中调用我们的异步loader,然后可行的时候在主组件的state中设置已加载的组件。

import PulpyLoader from 'Components/Chunks/Pulpy';

class MyComponent {  
  componentWillMount() {
    PulpyLoader().then(({ pulpy }) => {
      this.setState({ pulpy });
    });
  }

  render() {
    return (
      <div>
        {!(‘pulpy’ in this.state) && <p>Loading, please wait !</p>}
        {‘pulpy’ in this.state && <this.state.pulpy />}
      </div>
    );
  }
}

一旦下载完成,Webpack 不会再次下载这个块,而该组件也随时可用。

原文:http://blog.netgusto.com/asynchronous-reactjs-component-loading-with-webpack/