React新特性-Lazy和Suspense(二)

系列目录

React.lazy 定义

React.lazy 函数能让你像渲染常规组件一样处理动态引入(的组件)。

什么意思呢?其实就是懒加载。其原理就是利用es6 import()函数。这个import不是import命令。同样是引入模块,import命令是同步引入模块,而import()函数动态引入。

当 Webpack 解析到该语法时,它会自动地开始进行代码分割(Code Splitting),分割成一个文件,当使用到这个文件的时候会这段代码才会被异步加载。

为什么代码要分割

当你的程序越来越大,代码量越来越多。一个页面上堆积了很多功能,也许有些功能很可能都用不到,但是一样下载加载到页面上,所以这里面肯定有优化空间。就如图片懒加载的理论。

import函数

//import 命令
import { add } from './math';

console.log(add(16, 26));

//import函数
import("./math").then(math => {
  console.log(math.add(16, 26));
});

动态 import() 语法目前只是一个 ECMAScript (JavaScript) 提案, 而不是正式的语法标准。预计在不远的将来就会被正式接受。http://es6.ruanyifeng.com/#docs/module#import

import函数示例

下面是import一个示例:

在test文件夹下新建两个文件

test.html代码如下:

<div id="root">
  页面无内容
</div>
<button id="btn">加载js</button>

<script>
  document.getElementById('btn').onclick=function(){
    import('./test.js').then(d=>{
      d.test()
    })
  }
</script>

test.js代码如下:

function test(){
  document.getElementById('root')
  root.innerHTML='页面变的有内容了'
}
export {test}

这时候打开web服务让页面以http的方式访问,http://192.168.1.2:8080/test.html

我们在chrome的开发者工具下的Network可以看到只请求了一个页面。

但是当我们点击加载js,你会发现test.js会以动态的方式加入到代码中,同时执行了test函数,使页面的内容发生了变化。

React.lazy和常用的三方包react-loadable,都是使用了这个原理,然后配合webpack进行代码打包拆分达到异步加载,这样首屏渲染的速度将大大的提高。

由于React.lazy不支持服务端渲染,所以这时候react-loadable就是不错的选择。

如何使用React.lazy

下面示例代码使用create-react-app脚手架搭建:

//OtherComponent.js 文件内容

import React from 'react'
const OtherComponent = ()=>{
  return (
    <div>
      我已加载
    </div>
  )
}
export default OtherComponent

// App.js 文件内容
import React from 'react';
import './App.css';
//使用React.lazy导入OtherComponent组件
const OtherComponent = React.lazy(() => import('./OtherComponent'));
function App() {
  return (
    <div className="App">
      <OtherComponent/>
    </div>
  );
}
export default App;

这是最简单的React.lazy,但是这样页面会报错。这个报错提示我们,在React使用了lazy之后,会存在一个加载中的空档期,React不知道在这个空档期中该显示什么内容,所以需要我们指定。接下来就要使用到Suspense

Suspense

如果在 App 渲染完成后,包含 OtherComponent 的模块还没有被加载完成,我们可以使用加载指示器为此组件做优雅降级。这里我们使用 Suspense 组件来解决。

这里将App组件改一改

import React, { Suspense, Component } from 'react';
import './App.css';
//使用React.lazy导入OtherComponent组件
const OtherComponent = React.lazy(() => import('./OtherComponent'));
export default class App extends Component {
  state = {
    visible: false
  }
  render() {
    return (
      <div className="App">
        <button onClick={() => {
          this.setState({ visible: true })
        }}>
          加载OtherComponent组件
        </button>
        <Suspense fallback={<div>Loading...</div>}>
          {
            this.state.visible
              ?
              <OtherComponent />
              :
              null
          }
        </Suspense>
      </div>
    )
  }
}

我们指定了空档期使用Loading展示在界面上面,等OtherComponent组件异步加载完毕,把OtherComponent组件的内容替换掉Loading上。

为了演示我把chrome网络调到Fast 3G,不然看不到loading出现。

可以从上面图片看出,当点击加载的时候,页面的head会插入<script charset="utf-8" src="/static/js/2.chunk.js"></script>这段代码,发出一个get请求,页面开始显示loading,去请求2.chunk.js文件。

请求结束返回内容就是OtherComponent组件的内容,只是文件名称和文件内容经过webpack处理过。

注意:Suspense使用的时候,fallback一定是存在且有内容的, 否则会报错。


文章作者: jackie chen
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 jackie chen !
评论
 上一篇
React新特性-memo(三) React新特性-memo(三)
父组件进行了setState,众所周知子组件都会进行重新渲染。React.memo会做浅层对比传入的props,如果传入的props没有改变,这个子组件就不会重新渲染。 React.memo 为高阶组件。它与 React.PureComp
2019-07-11
下一篇 
React新特性-Context(一) React新特性-Context(一)
Context提供了一种方式,能够让数据在组件树种传递而不必使用Props一级一级手动传递 系列目录 React新特性-Context(一) React新特性-Lazy和Suspense(二) React新特性-memo(三) Reac
2019-07-07
  目录