使用 React.Suspense 和 React.lazy() 实现 Code Splitting

2,254 阅读4分钟
原文链接: mp.weixin.qq.com

当前浏览器不支持播放音乐或语音,请在微信或其他浏览器中播放 Suspense Axodry - You (I'll See You in My Dreams)

没错,又是 Code Splitting,这次的方案适用于较新版本的 React。之前有介绍到 react-loadable,源于社区的力量,而这次要介绍的是 React 官方的 code splitting 解决方案。  

React 在 16.6 的版本中引入了一个新的 feature:React.Suspense,它和 React.lazy() 方法组成一对,用来实现 React 组件的代码分割及懒加载。  

Getting Start | 开始

首先需要注意的一点是,你得保证项目的 React 版本至少是 16.6,如果是新项目倒不必对于这点太过费神,如果是老项目的话,你需要进行版本升级

接下来,你需要在对应的组件中引入 Suspense 和 lazy 方法:

About Code Splitting | 关于代码分割

值得一提的是,虽然使用 Suspense 和 lazy 可以让你轻而易举的实现组件的懒加载,但是如果你仍将整个项目打包到一个 bundle 文件中时,你可能看不到多少好处。  

虽然这篇文章没有提到,但还是建议你去webpack 的官方文档中阅读关于 code splitting 的章节。

React.lazy()

lazy() 方法接受一个动态 import 函数作为参数,它的作用是将其他组件引入,就像这样:  

因为 import 被一个函数包裹在内并传递给了 lazy(),在我们真正使用到对应的组件之前它是不会加载的,这和直接在文件的一开始就引入组件是有很大差别的。

React.Suspense

React.Suspense 组件允许我们将另一个组件包裹起来,并指定一个 fallback 组件,后者会在被包裹组件加载时展现出来: 

我们总是需要在异步加载其他组件时,提供给用户一个 loading 的交互。  

即使在某些场景下你所用到的组件体积并不很大,但懒加载仍能在弱网环境下起到明显的作用,毕竟我们不能保证每个用户都使用着速度最快的网络。 

Putting It All Together | 合体!

为了明显的感知到 React.Suspense 和 React.lazy() 的作用,我们需要创造一个例子,一个既简单又做作的例子。我们至少需要两个文件,其中一个就是我们基本的 React app “样板文件”,另一个是需要被我们懒加载进来的组件文件。  

简单起见,我们撸一个短小精悍的 logo 组件:

接下来是我们的 App.js ,与此同时,为了能手动的触发异步组件的加载,我们需要一些简单的逻辑处理:  

正如你所看到的这样,使用 React.Suspense 和 React.lazy() 并不是一件复杂的事情,正因为如此,用它来重构现有的项目并不会花费太大的功夫,如果你已经根据业务场景把组件划分为不同的文件了,这个过程将会变得更简单。

Error Boundary | 错误边界

我们可能会碰到一些不可预见的引用错误问题,为了更好的体验,我们依然需要去处理程序出错的场景。ErrorBoundary 就是为此而生的,它也是 React v16.6 中新提出的一个概念:一旦一个组件定义了 static getDerivedStateFromError() 或  componentDidCatch() 时,它就可以被称为一个 ErrorBoundary 组件,前者用来在出错时显示对应的 UI,后者用来获取错误信息。  

总而言之,ErrorBoundary 组件可以做到 write once, run anywhere,这里不讲述太多关于 ErrorBoundary 的东西,直接上代码,首先,创建一个 ErrorBoundary 组件:  

然后就可以用它来处理懒加载组件时的错误场景了: 

Route-based Code Splitting | 基于路由的代码分割

截止目前我们知道了如何借助这两个新特性实现组件的懒加载。现在要更进一步 —— 基于路由的 code splitting,话不多说,直接上代码: 

Conclusion | 总结

React.Suspense 和 React.lazy() 的提出为现代 React 应用的性能优化和工程化提供了条便捷之路。  

不过正所谓金无足赤,截止目前,Suspense 并不能在 SSR 中使用。

参考文章:

1. https://alligator.io/react/code-splitting-with-react-suspense/

2. https://reactjs.org/docs/error-boundaries.html