翻译自原文:https://medium.freecodecamp.org/how-to-use-react-lazy-and-suspense-for-components-lazy-loading-8d420ecac58
React 16.6将代码分割(code-splitting)带到了一个新的level。您现在可以在真正需要时加载组件,且无需安装其他依赖库。
什么是代码分割(code-splitting)和懒加载(lazy-loading)?
Webpack是这样定义代码分割的:
"将代码拆分为各种捆绑包,然后按需加载或并行加载的技术。" - 链接
另一种说法是:“按需加载或并行加载”是懒加载,与懒加载相反的是预加载(或立即加载)(eager-loading)。总之,无论你是否使用它,一切都会被加载。
为什么我们要使用代码分割和懒加载?
有时我们必须引入大量代码来完成某些功能,这些代码可以是来自第三方依赖库或者自行编写。总之,这些代码会影响主包的大小。
下载几MB文件对于今天的互联网速度来说是小菜一碟,但是我们仍然需要考虑网速较慢或使用移动数据的用户。
(在评论席还补充了:这里不仅仅只影响文件大小,对于添加的JavaScript每一个字节,都会增加内存和CPU使用率。- 相关链接)
它们在React 16.6之前是如何实现的?
对于懒加载React组件最流行的库可能是react-loadable
⚠️需要注意的是,在服务端渲染上reactjs.org仍然建议使用可加载组件(Loadable Components)。- 相关链接
使用上,react-loadable
和React的新方法非常相似,我将在下文中进行演示。
对于环境配置还需要做什么?
让我们看看reactjs.org对此有何看法:
“如果您正在使用Create React App,Next.js,Gatsby或类似的工具,您将拥有一个开箱即用的Webpack配置来打包您的应用程序”
如果不是,您需要自己配置打包文件。例如,请参阅Webpack文档的“安装
和入门”指南。 - reactjs.org
好的,所以需要Webpack,它处理捆绑包的动态导入。
本文将使用create-react-app
脚手架生成以下演示案例,所以Webpack已经配置好了,来吧!
Demo
本演示将使用react-pdf。react-pdf
是一个很棒的库,用于在浏览器、移动端和服务器上创建PDF文件。一般我们都在服务器上生成PDF,但是如果我们需要在客户端进行,则需要一个成本:包大小。
我正在使用Visual Studio Code的Import cost插件来展示依赖库的大小。
首先,假设我们的需求是在用户点击按钮时生成PDF文件。
其次,如果这是一个很大的web app以及这个功能可能是很小一部分,也许是用户不经常使用的功能。每次页面请求都会加载整个react-pdf
代码就变得无意义了。
所以,我们非常需要一个延迟加载的解决方案。
预加载 VS 懒加载 展示
一个简易的PDFPreview组件
import React from "react";
import { PDFViewer, Document, Page, Text, View } from "@react-pdf/renderer";
import pdfstyles from "./pdfStyles";
// Create Document Component
const PDFPreview = ({ title }) => (
{title}
This is a text in a generated PDF file.
);
export default PDFPreview;
添加样式
import { StyleSheet } from "@react-pdf/renderer";
const styles = StyleSheet.create({
viewer: {
padding: 0
},
page: {
margin: 0,
flexDirection: "row",
backgroundColor: "#ffffff"
},
title: {
fontSize: 30,
marginBottom: 30
},
section: {
margin: 10,
padding: 10,
flexGrow: 1
}
});
export default styles;
预加载
让我们看看没有延迟加载的父组件
import React, { Component } from "react";
import PDFPreview from "./PDFPreview";
class App extends Component {
state = {
name: "",
showPDFPreview: false
};
handleClick = () => this.setState({ showPDFPreview: true });
handleNameChange = event => this.setState({ name: event.target.value });
render() {
const greeting = `Hello ${this.state.name}`;
return (
{this.state.showPDFPreview && }
);
}
}
export default App;
在浏览器中将呈现以下视图
无论我们是否点击生成PDF,与其相关的所有代码都包含在应用包内了
这是一个开发环境。在打包之后,Size将显著缩小。尽管如此,我们还是没有最佳地分割代码。
懒加载
import React, { Component, Suspense } from "react";
const LazyPDFDocument = React.lazy(() => import("./PDFPreview"));
class App extends Component {
state = {
name: "",
showPDFPreview: false
};
handleClick = () => this.setState({ showPDFPreview: true });
handleNameChange = event => this.setState({ name: event.target.value });
render() {
const greeting = `Hello ${this.state.name}`;
return (
{this.state.showPDFPreview && (
Loading... }>
)}