动态import
在说lazy
和suspense
之前,还是先说说动态import这种语法。
import
语句我们使用的很多,通常是import ... from '...'
这样的写法,这样的写法也被称作是静态加载。
而所谓的动态import或者说动态加载,就是指在运行时加载。写法如下:
import('./test.js').then(test => {
...
});
可以发现,动态import实现了Promise规范,回调函数的test
参数就是加载完成后的模块。
这么写有什么好处呢?一个页面中也许会有许多的逻辑代码并不需要在页面加载时加载,也许是在触发了某个事件如点击之后才需要加载。那么通过动态加载就可以实现这一点,好处在于可以加快页面加载的速度。
lazy
对于一段JS代码,我们可以在需要的时候通过动态import的方式异步加载,那么对于一个React模块,什么是“需要的时候”?到了这个时候又该怎么加载呢?
对于React模块,这个“需要的时候”自然就是要渲染它的时候,而想要在这个时候实现异步加载就需要使用React 16.6中新增的lazy
方法了。
lazy
是一个方法,它封装了“动态加载的过程”,如果对这句话不太明白,看下面的代码就能理解:
import React, { lazy, Component } from 'react';
const Later = lazy(() => import('./Later'));
上面代码中的Later
是一个React组件,但它并不能被渲染,它只是一个“动态加载过程”的封装。它在要被渲染的时候就会去加载真正的Later
组件。
lazy
方法接受一个无参数的函数,函数必须执行动态import。
那是不是直接这样使用就可以了呢?
import React, { lazy, Component } from 'react';
const Later = lazy(() => import('./Later'));
export default class App extends Component {
render() {
return (
<div>
<Later />
</div>
);
}
}
可以发现在浏览器中是会报错的:
出现这个报错就需要用到suspense
了。
suspense
既然是动态加载,那么也就是说会有一个加载过程,那么在这个加载过程中就需要一个UI组件,来在等待过程中显示一些UI。
import React, { Component, lazy, Suspense } from 'react';
const Later = lazy(() => import('./Later'));
export default class App extends Component {
render() {
return (
<div>
<Suspense fallback={<div>loading...</div>}>
<Later />
</Suspense>
</div>
);
}
}
这样就会在Later
加载完成之前显示“loading…”字样。
suspense
组件有一个fallback
属性,它就是用来接收加载过程中显示的组件的。suspense
内部是可以包裹多个组件的。
Error boundaries
Error boundaries,中文意为错误边界。我们希望部分UI的错误不会导致整个程序的崩溃,以及希望在错误发生时能够显示对应的UI。
错误边界是一种 React 组件,这种组件可以捕获并打印发生在其子组件树任何位置的 JavaScript 错误,并且,它会渲染出备用 UI,而不是渲染那些崩溃了的子组件树。错误边界在渲染期间、生命周期方法和整个组件树的构造函数中捕获错误。
如果一个 class 组件中定义了 static getDerivedStateFromError()
或 componentDidCatch()
这两个生命周期方法中的任意一个(或两个)时,那么它就变成一个错误边界。当抛出错误后,请使用 static getDerivedStateFromError() 渲染备用 UI ,使用 componentDidCatch() 打印错误信息。
getDerivedStateFromError
此生命周期会在后代组件抛出错误后被调用。 它将抛出的错误作为参数,并返回一个值以更新 state。
注:getDerivedStateFromError() 会在渲染阶段调用,因此不允许出现副作用。 如遇此类情况,请改用 componentDidCatch()。
componentDidCatch
此生命周期在后代组件抛出错误后被调用。 它接收两个参数:
- error —— 抛出的错误。
- info —— 带有 componentStack key 的对象,其中包含有关组件引发错误的栈信息。
注:componentDidCatch() 会在“提交”阶段被调用,因此允许执行副作用。 它应该用于记录错误之类的情况。
import React, { Component } from 'react';
export default class MyError extends Component {
constructor(props){
super(props);
this.state = {
hasError: false
};
}
static getDerivedStateFromError(err){
return {hasError: true};
}
componentDidCatch(err, errinfo){
console.log(err);
console.log(errinfo);
}
render() {
const { hasError } = this.state;
if(hasError){
return <div>Something wrong!!!</div>
}
return this.props.children;
}
}