使用 React.lazy 和 Suspense 进行代码拆分

您永远不需要向用户分发超出必要的代码,因此请对软件包进行拆分,以确保这种情况永远不会发生!

使用 React.lazy 方法可轻松对 React 应用进行代码拆分, 动态导入。

import React, { lazy } from 'react';

const AvatarComponent = lazy(() => import('./AvatarComponent'));

const DetailsComponent = () => (
  <div>
    <AvatarComponent />
  </div>
)

为什么搜索渠道报告非常实用?

大型 React 应用通常由许多组件、实用程序 方法和第三方库。如果没有尝试加载 一个大型应用的不同部分 在用户加载 首页。这可能会严重影响网页性能。

React.lazy 函数提供了一种内置方式来分隔 将应用拆分成单独的 JavaScript 块,几乎不用费力。您可以 然后在与 Suspense 结合使用时处理加载状态 组件。

悬疑

向用户传送大量 JavaScript 有效负载的问题在于, 网页完成加载所需的时间,尤其是在性能较低的设备上 和网络连接正因如此,代码拆分和延迟加载才 非常有用。

不过,在加载和编辑内容时, 代码拆分组件是通过网络提取的,因此请务必 显示有用的加载状态。将 React.lazySuspense 搭配使用 有助于解决此问题。

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 的代码很小, 说明加载旋转图标为何仅显示一小段时间。更大 组件可能需要更长时间才能加载完毕 网络连接信号较弱

为了更好地演示此操作的工作原理:

  • 如需预览网站,请按查看应用。然后按 全屏 全屏
  • 按 `Ctrl+Shift+J`(在 Mac 上,按 `Command+Option+J`)打开开发者工具。
  • 点击网络标签页。
  • 点击限制下拉菜单,其默认设置为无限制。选择 Fast 3G
  • 点击应用中的 Click Me 按钮。

加载指示器现在会显示更长时间。请注意 构成了 AvatarComponent 作为单独的分块进行提取。

<ph type="x-smartling-placeholder">
</ph> 显示正在下载一个 chunk.js 文件的开发者工具网络面板

挂起多个组件

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 请按以下步骤操作:

  1. 从路线级别开始。路线是标识某地点的点的最简单方法 以及可拆分的应用通过 React 文档 展示了如何将 Suspensereact-router
  2. 找出您网站上的网页上是否存在仅在 某些用户互动(例如点击某个按钮)。拆分这些内容 最大程度地减少 JavaScript 载荷。
  3. 考虑拆分屏幕外的其他内容, 用户。