使用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 以查看本文中的代码的实际应用!