使用ReactSuspense进行代码拆分
React.Suspense 以及 v16.6 中引入的 React.lazy() 添加了新功能,允许组件在实际渲染之前等待某些内容。 这项新功能使 React 组件的代码拆分和延迟加载变得轻而易举!
入门
要开始使用,您需要确保您使用的是 React v16.6 或更高版本。 如果您正在开始一个新项目,或者如果您正在使用不在正确版本上的旧项目,只需:
# Via npm $ npm install --save react react-dom # Or via Yarn $ yarn add react react-dom
然后在您想要处理其他组件的延迟加载的组件中,导入 Suspense 和 lazy:
import React, { lazy, Suspense } from 'react';
关于代码拆分
值得指出的是,虽然 Suspense 和 lazy 允许您快速轻松地延迟加载组件,但如果您将整个应用程序捆绑到一个单独的应用程序中,您可能看不到太多好处像 Webpack 这样的脚本。
虽然超出了本文的范围,但您可以在 Webpack 文档 中阅读有关使用 Webpack 进行代码拆分的内容。
React.lazy()
lazy() 方法将一个函数作为第一个参数,该参数预计将 import 另一个组件,如下所示:
const SomeComponent = lazy(() => import('./SomeComponent');
因为 import 在传递给 lazy() 的函数内部,所以在我们实际使用组件之前不会加载组件,而不是在顶部急切地加载其他导入你的文件。
React.Suspense
React.Suspense 组件允许我们包装一个组件并指定一个 fallback 组件,该组件将在包装的组件加载时显示:
<Suspense fallback={<div>Loading...</div>}>
<SomeComponent />
</Suspense>
当您加载较大的组件或发生在 import 大型库(如 react-pdf 或 react-draft-wysiwyg)的组件时,这尤其有用。
即使您的组件不在重量级部门,延迟加载也可以帮助可能没有最佳 Internet 连接的最终用户。
把它们放在一起
要真正体验使用 React.Suspense 和 React.lazy(),我们将需要两个单独的文件。 一个只是我们基本的 React 应用程序样板,另一个是我们将延迟加载的组件。
让我们从我们将要使用的组件开始 import。 在这个例子中,我创建了一个非常简单的组件来加载总是简洁的 Alligator.io 标志:
AlligatorioLogo.jsx
import React from "react";
function AlligatorioLogo() {
const imageSource = "https://uploads.codesandbox.io/uploads/user"
+ "/39d6d9f6-60d2-4a60-9eb7-9250c3417bef"
+ "/saY6-alligatorio-logo.png";
return (
<img
alt="Alligator.io Logo"
src={imageSource}
width="250"
/>
);
}
export default AlligatorioLogo;
接下来是我们应用程序的样板代码和一小部分状态逻辑,以便我们可以手动触发组件的加载:
应用程序.jsx
import React, { Component, Fragment, lazy, Suspense } from "react";
import { render } from "react-dom";
import "./styles.css";
const AlligatorioLogo = lazy(() => import("./AlligatorioLogo"));
class App extends Component {
constructor(props) {
super(props);
this.state = {
showLogo: false
};
}
onClick = () => {
this.setState({ showLogo: !this.state.showLogo });
};
render() {
return (
<div className="App">
<h1>React.lazy() + <React.Suspense /> Demo</h1>
<div>
<button onClick={this.onClick}>
{this.state.showLogo &&
<Fragment>Click to Hide the Logo</Fragment>
}
{!this.state.showLogo && (
<Fragment>Click to Show the Logo</Fragment>
)}
</button>
</div>
<hr />
{this.state.showLogo && (
<Suspense fallback={<div>Loading...</div>}>
<AlligatorioLogo />
</Suspense>
)}
</div>
);
}
}
const container = document.createElement("div");
document.body.appendChild(container);
render(<App />, container);
如您所见,使用 Suspense 和 lazy() 真的没什么用。 由于它非常简单,将现有系统移植到它不应该是太大的负担,特别是如果您已经将组件拆分为单独的文件。
结论
React.lazy() 和 React.Suspense 的引入是在帮助减少构建现代 Web 应用程序所需编写的样板代码量方面向前迈出的重要一步。
Suspense 虽然已经相当强大,但也不是没有缺点。 未来 v16 版本的 React 路线图上最大的缺失部分是使用 Suspense 进行数据获取的能力。
一旦此数据获取功能可用,Suspense 将能够等待诸如 AJAX 调用之类的事情,并在加载时显示备用组件。
还值得注意的是,Suspense 还没有完全准备好与服务器端渲染一起使用。
如果您准备好试一试 React.Suspense 和 React.lazy(),您可以前往 CodeSandbox 以查看本文中的代码的实际应用!