使用 React.lazy() 实现按需加载组件,提高应用性能!

lxf2023-12-21 07:00:02

阅读时间约 11 分钟。


我们开发的 React 应用随着规模越来越大,如果还是将所有组件打包到一个 bundle 文件中,就可能会导致应用程序的加载时间变慢。常见的做法是,将程序中的组件打包到单独的文件中以减少应用的加载时间,通常我们会通过“按需加载”的方式来实现这一目的。在本文中,你将学会在 React 程序中关于组件动态导入的相关知识。

1. 什么是动态导入组件?

动态导入组件是指在需要时才加载组件,而不是在应用程序加载时将所有组件都打包到一个 bundle 文件中。在 React 中,我们该如何实现呢?

React 为我们提供了一个 lazy() 方法和 Suspense 组件,这是实现动态导入组件的两个主要工具。

使用 React.lazy(),我们可以轻松地实现按需加载组件,它的语法如下:

const MyComponent = React.lazy(() => import('./MyComponent'));

在上面的代码中,React.lazy() 接收一个函数,该函数返回一个 import() 函数调用。import() 函数是 ECMAScript 动态导入语法的一部分,它允许我们在运行时异步加载一个模块。通过将 React.lazy() 和 import() 函数结合使用,我们便可以按需加载组件。

当我们使用 React.lazy() 时,React 会自动将返回的组件包装在一个 lazy 组件中。因此,我们需要使用 Suspense 组件来渲染这个 lazy 组件。Suspense 组件允许我们在组件加载完成之前显示一个 loading 界面。下面是一个使用 React.lazy() 和 Suspense 组件的简单例子

import React, { lazy, Suspense } from 'react';

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

function App() {
  return (
    <div>
      <Suspense fallback={<div>Loading...</div>}>
        <MyComponent />
      </Suspense>
    </div>
  );
}

在上面的代码中,当 <MyComponent /> 组件被渲染时,React 将自动异步加载 MyComponent 模块。fallback 属性指定了当组件加载时显示的 loading 界面。当组件加载完成时,React 将自动将其呈现。

2. 异步列表组件示例

下面我们通过一个「异步列表」组件示例来演示 React.lazy() 和 Suspense,先看最终的效果:

使用 React.lazy() 实现按需加载组件,提高应用性能!

2.1 父组件 ArtistPage

我们通过一个父组件 ArtistPage 和一个子组件 Albums 来实现上面 gif 中的效果。父组件 ArtistPage 实现思路如下:

  1. 页面加载完成后,默认渲染「Open The Beatles artist page」按钮,如果按钮被点击则展示列表数据;
  2. 在展示列表数据前,首先通过 Suspense 展示一个过渡用的 Loading 页面,当子组件和其中的数据请求完成后再展示列表数据。

父组件 ArtistPage 代码如下:

import { Suspense, useState } from "react";

import Albums from "@/components/Albums";

export default function ArtistPage() {
  const [show, setShow] = useState(false);

  // 定义组件的状态 show,控制组件的渲染
  // 初始时设置为 false,点击按钮后设置为 true
  // 以展示 The Beatles 的专辑页面
  if (show) {
    // 如果 show 为 true,则渲染以下内容
    return (
      <>
        <h1>The Beatles</h1>
        {/* 使用 React Suspense 包装组件,添加 fallback UI */}
        <Suspense fallback={<Loading />}>
          {/* 传入 artistId 属性,渲染 The Beatles 的专辑 */}
          <Albums artistId="the-beatles" />
        </Suspense>
      </>
    );
  } else {
    // 如果 show 为 false,则渲染以下按钮
    return (
      <button onClick={() => setShow(true)}>
        Open The Beatles artist page
      </button>
    );
  }
}

// 定义 Loading 组件,用于在数据加载时显示
function Loading() {
  return <h2>