iT邦幫忙

2023 iThome 鐵人賽

DAY 22
0
Modern Web

react 學習記錄系列 第 22

[Day22]我的 react 學習記錄 - lazy & Suspense

  • 分享至 

  • xImage
  •  

這篇文章的主要內容

簡單介紹 lazy 跟 Suspense 的用途跟用法


lazy

lazy 是 react 裡面提供的一個 api 可以讓我們透過非同步的方式載入 JavaScript,隨著專案的發展可能會有很多分頁跟資料,如果要在用戶第一次進到網頁時就全部進行載入可能會有很長的讀取跟解析時間。

import { useState } from "react";
import PageOne from "./PageOne";
import PageTwo from "./PageTwo";

function App() {
  const [page, setPage] = useState("");
  function handlePage(page: string) {
    setPage(page);
  }
  return (
    <div>
      <div>
        <button onClick={() => handlePage("PageOne")}>One</button>
        <button onClick={() => handlePage("PageTwo")}>Two</button>
      </div>
      {
        {
          "": <>HOME</>,
          PageOne: <PageOne />,
          PageTwo: <PageTwo />,
        }[page]
      }
    </div>
  );
}

我在 App 裡面引入了 PageOne 跟 PageTwo 兩個元件,透過 button 來控制要顯示哪個元件。

在 pagOne 跟 pageTwo 裡面分別載入了較大的 json 檔案。

// PageTwo 的內容基本上相同。
import data from "../public/data-1.json";

function PageOne() {
  console.log("data", data);
  return <div>Here is Page One!!!</div>;
}

export default PageOne;

打開瀏覽器開發者工具,點擊 network 的分頁可以看到載入了哪些檔案。

https://ithelp.ithome.com.tw/upload/images/20230929/20161583LLCwTnolRN.png

可以看到即使畫面沒有顯示元件,但是一樣把元件也一起載入了,當然裡面如果有引入比較大的檔案也會一起事先載入,透過 lazy 就可以在需要的時候再載入你的 react 元件。

Syntax

const SomeComponent = lazy(load)

load: 一個 function 回傳 Promise 物件或其他 thenable 的物件,react 只會呼叫這個 function 在這個元件需要被放在畫面上的時候,react 只會呼叫一次並把回傳的結果保留下來,不會重複呼叫相同的內容。

SomeComponent: 回傳可以被非同步載入的 react 元件。

注意事項

  • lazy 並不是 react hook,請不要在元件內部使用,在元件外使用,當作在引入一個 react 元件。
  • 引入的元件必須要是那個 js 檔 default export 的內容。
  • 改變成非同步引入之後會需要處理 pendingfulfilledrejected 時候畫面應該如何處理,所以通常會搭配 react 提供的 Suspense 元件。

Suspense Component

<Suspense><Fragment> (<>...</>) 一樣都是 react 提供的元件,Suspense 讓我們在元件在載入的過程中有預設的內容可以顯示。

Syntax

<Suspense fallback={<Loading />}>
  <SomeComponent />
</Suspense>

Suspense 元件接收兩個 props,childrenfallback

children: 希望可以非同步載入的元件跟內容,如果元件還在解析的話會先顯示 fallback 的內容。
fallback: 一個備用的元件,讓我們在 children 還在載入的過程時可以保持正常的 render 流程,Suspense 元件會自動的在這兩個 props 中進行切換。

簡單看過了 lazy 跟 Suspense 的用法之後就可以讓我們上面的元件做到非同步的載入了。

import { useState, lazy, Suspense } from "react";
const PageOne = lazy(() => import("./PageOne"));
const PageTwo = lazy(() => import("./PageTwo"));

function Loading() {
  return <p>Loading...</p>;
}

function App() {
  const [page, setPage] = useState("");
  function handlePage(page: string) {
    setPage(page);
  }
  return (
    <div>
      <div>
        <button onClick={() => handlePage("PageOne")}>One</button>
        <button onClick={() => handlePage("PageTwo")}>Two</button>
      </div>
      {
        {
          "": <>HOME</>,
          PageOne: (
            <Suspense fallback={<Loading />}>
              <PageOne />
            </Suspense>
          ),
          PageTwo: (
            <Suspense fallback={<Loading />}>
              <PageTwo />
            </Suspense>
          ),
        }[page]
      }
    </div>
  );
}

本來的 import 改成了 const PageOne = lazy(() => import("./PageOne")); 的形式。
另外也多了 Loading 的元件放在 <Suspense fallback={<Loading />}> 裡面。

lazy

可以看到當我載入畫面的時候 PageOne 跟 PageTwo 還有裡面 import 的檔案都沒有被載入,而是等到我點擊按鈕切換元件的時候才被載入,而且已經被載入的元件就不會重複的載入,透過非同步載入的方式可以大大的提高網頁的效能跟載入速度。


lazy - react document
<Suspense> - react document

下一篇會介紹 react 常用的相關套件 - react router
如果內容有誤再麻煩大家指教,我會盡快修改。

這個系列的文章會同步更新在我個人的 Medium,歡迎大家來看看 👋👋👋
Medium


上一篇
[Day21]我的 react 學習記錄 - useCallback
下一篇
[Day23]我的 react 學習記錄 - react router
系列文
react 學習記錄30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言