您永远不需要向用户交付不必要的代码,因此请拆分您的 bundle,确保这种情况永远不会发生!
React.lazy 方法可让您轻松使用动态导入在组件级别对 React 应用进行代码拆分。
import React, { lazy } from 'react';
const AvatarComponent = lazy(() => import('./AvatarComponent'));
const DetailsComponent = () => (
<div>
<AvatarComponent />
</div>
)
为什么搜索渠道报告非常实用?
大型 React 应用通常由许多组件、实用方法和第三方库组成。如果不尝试仅在需要时加载应用的不同部分,那么用户在加载第一个网页时,就会收到一个庞大的 JavaScript 软件包。这可能会对网页性能产生重大影响。
React.lazy 函数提供了一种内置方法,只需极少的工作量,即可将应用中的组件拆分为单独的 JavaScript 块。然后,您可以将其与 Suspense 组件结合使用,以处理加载状态。
悬疑
向用户传送大型 JavaScript 载荷的问题在于,网页加载完成所需的时间较长,尤其是在设备和网络连接较弱的情况下。这就是代码拆分和延迟加载非常实用的原因。
不过,通过网络提取代码拆分组件时,用户始终会遇到轻微的延迟,因此显示有用的加载状态非常重要。将 React.lazy 与 Suspense 组件搭配使用有助于解决此问题。
import React, { lazy, Suspense } from 'react';
const AvatarComponent = lazy(() => import('./AvatarComponent'));
const renderLoader = () => <p>Loading</p>;
const DetailsComponent = () => (
<Suspense fallback={renderLoader()}>
<AvatarComponent />
</Suspense>
)
Suspense 接受 fallback 组件,该组件可让您将任何 React 组件显示为加载状态。以下示例展示了其运作方式。
只有在点击按钮时,系统才会呈现头像,然后发出请求来检索暂停的 AvatarComponent 所需的代码。
与此同时,系统会显示后备加载组件。
在这里,构成 AvatarComponent 的代码很小,这就是“正在加载”旋转图标仅显示很短时间的原因。较大的组件可能需要更长时间才能加载,尤其是在网络连接较弱的情况下。
为了更好地演示其工作原理,请参考以下示例:
- 如需预览网站,请按查看应用。然后按全屏
。
- 按 `Control+Shift+J`(在 Mac 上,按 `Command+Option+J`)打开开发者工具。
- 点击网络标签页。
- 点击限制下拉菜单,该菜单默认设置为不限制。选择快速 3G。
- 点击应用中的 Click Me 按钮。
现在,加载指示器的显示时间会更长。请注意,构成 AvatarComponent 的所有代码是如何作为单独的分块提取的。
暂停多个组件
Suspense 的另一个功能是,它允许您暂停加载多个组件,即使它们都是延迟加载的。
例如:
import React, { lazy, Suspense } from 'react';
const AvatarComponent = lazy(() => import('./AvatarComponent'));
const InfoComponent = lazy(() => import('./InfoComponent'));
const MoreInfoComponent = lazy(() => import('./MoreInfoComponent'));
const renderLoader = () => <p>Loading</p>;
const DetailsComponent = () => (
<Suspense fallback={renderLoader()}>
<AvatarComponent />
<InfoComponent />
<MoreInfoComponent />
</Suspense>
)
这是一种非常实用的方法,可延迟多个组件的渲染,同时仅显示单个加载状态。所有组件都提取完毕后,用户会看到它们同时显示。
您可以通过以下嵌入内容看到这一点:
否则,很容易遇到交错加载问题,即界面的不同部分一个接一个地加载,每个部分都有自己的加载指示器。这可能会让用户体验感觉更加突兀。
处理加载失败
Suspense 允许您在后台发出网络请求时显示临时加载状态。但如果这些网络请求因某种原因而失败,该怎么办?您可能处于离线状态,或者您的 Web 应用可能正在尝试延迟加载版本化网址,该网址已过时,并且在服务器重新部署后不再可用。
React 有一个标准模式,可妥善处理这些类型的加载失败:使用错误边界。如文档中所述,任何 React 组件只要实现生命周期方法 static getDerivedStateFromError() 或 componentDidCatch()(或两者),都可以充当错误边界。
如需检测和处理延迟加载失败,您可以使用父组件封装 Suspense 组件,作为错误边界。在错误边界的 render() 方法中,如果没有错误,您可以按原样渲染子组件;如果出现问题,则可以渲染自定义出错提示:
import React, { lazy, Suspense } from 'react';
const AvatarComponent = lazy(() => import('./AvatarComponent'));
const InfoComponent = lazy(() => import('./InfoComponent'));
const MoreInfoComponent = lazy(() => import('./MoreInfoComponent'));
const renderLoader = () => <p>Loading</p>;
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = {hasError: false};
}
static getDerivedStateFromError(error) {
return {hasError: true};
}
render() {
if (this.state.hasError) {
return <p>Loading failed! Please reload.</p>;
}
return this.props.children;
}
}
const DetailsComponent = () => (
<ErrorBoundary>
<Suspense fallback={renderLoader()}>
<AvatarComponent />
<InfoComponent />
<MoreInfoComponent />
</Suspense>
</ErrorBoundary>
)
总结
如果您不确定从何处开始对 React 应用应用代码拆分,请按以下步骤操作:
- 从路线级别开始。路由是确定应用中可拆分点的最简单方法。React 文档展示了如何将
Suspense与react-router搭配使用。 - 找出网站页面上仅在发生特定用户互动(例如点击按钮)时才会呈现的所有大型组件。拆分这些组件可最大限度地减少 JavaScript 载荷。
- 考虑拆分屏幕外且对用户不重要的任何其他内容。