การแยกโค้ดด้วย React.lazy และ Suspense

คุณไม่จำเป็นต้องส่งโค้ดมากเกินกว่าที่จำเป็นให้กับผู้ใช้ ดังนั้นให้แยกแพ็กเกจกันเพื่อไม่ให้เกิดปัญหานี้ขึ้น

เมธอด 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 ขนาดใหญ่ให้กับผู้ใช้คือความยาวของ เวลาที่ใช้ในการโหลดหน้าเว็บให้เสร็จสิ้น โดยเฉพาะในอุปกรณ์ที่มีประสิทธิภาพต่ำ และเครือข่าย นี่จึงเป็นเหตุผลที่การแยกโค้ดและการโหลดแบบ Lazy Loading มีประโยชน์อย่างยิ่ง

แต่อาจมีความล่าช้าเล็กน้อยที่ผู้ใช้จะต้องพบเมื่อ มีการดึงข้อมูลคอมโพเนนต์แยกโค้ดผ่านเครือข่าย ดังนั้นจึงเป็นสิ่งสำคัญที่ แสดงสถานะการโหลดที่เป็นประโยชน์ กำลังใช้ 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 ซึ่งช่วยให้คุณแสดงรีแอ็กชันได้ เป็นสถานะการโหลด ตัวอย่างต่อไปนี้แสดงวิธีการใช้งาน อวาตาร์จะแสดงผลเมื่อมีการคลิกปุ่ม ซึ่งจะแสดง ทำให้สามารถเรียกรหัสที่จำเป็นสำหรับ AvatarComponent ที่ถูกระงับ ในระหว่างนี้ คอมโพเนนต์การโหลดสำรองจะแสดงขึ้นมา

โค้ดที่รวมกันเป็น AvatarComponent จะมีขนาดเล็ก ซึ่ง เหตุใดไอคอนหมุนจึงแสดงเพียงระยะเวลาสั้นๆ ใหญ่ขึ้น อาจใช้เวลาโหลดนานกว่ามาก โดยเฉพาะเมื่อ การเชื่อมต่อเครือข่ายที่สัญญาณอ่อน

หากต้องการสาธิตวิธีการทำงานที่ดียิ่งขึ้น ให้ทำดังนี้

  • หากต้องการดูตัวอย่างเว็บไซต์ ให้กดดูแอป แล้วกด เต็มหน้าจอ เต็มหน้าจอ
  • กด "Control+Shift+J" (หรือ "Command+Option+J" ใน Mac) เพื่อเปิดเครื่องมือสำหรับนักพัฒนาเว็บ
  • คลิกแท็บเครือข่าย
  • คลิกเมนูแบบเลื่อนลงการควบคุม ซึ่งตั้งค่าเป็นไม่มีการควบคุมโดยค่าเริ่มต้น เลือก Fast 3G
  • คลิกปุ่มคลิกฉันในแอป

สัญญาณบอกสถานะการโหลดจะแสดงเป็นเวลานานกว่าปกติแล้ว โปรดสังเกตว่าโค้ดทั้งหมดที่ ที่รวมกันแล้วจะมีการดึงข้อมูล AvatarComponent เป็นกลุ่มแยกต่างหาก

วันที่ แผงเครือข่ายของเครื่องมือสำหรับนักพัฒนาเว็บที่แสดงไฟล์ chunk.js ที่กำลังดาวน์โหลด

กำลังระงับหลายคอมโพเนนต์

อีกฟีเจอร์หนึ่งของ Suspense คือช่วยให้คุณระงับ คอมโพเนนต์ไม่ให้โหลดได้ แม้ว่าจะเป็นการโหลดแบบ Lazy Loading ทั้งหมด

เช่น

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>
)

วิธีนี้เป็นประโยชน์อย่างยิ่งในการหน่วงเวลาการแสดงผลหลายคอมโพเนนต์ในขณะที่ การแสดงเพียงสถานะการโหลดเดียวเท่านั้น เมื่อคอมโพเนนต์ทั้งหมดเสร็จแล้ว การดึงข้อมูล ผู้ใช้จะเห็นสิ่งเหล่านั้นแสดงพร้อมกันทั้งหมด

คุณสามารถดูได้จากการฝังต่อไปนี้

หากไม่มีสิ่งนี้ คุณอาจพบปัญหาการโหลดกระตุกได้ง่ายๆ หรือ ส่วนต่างๆ ของ UI ที่โหลดทีละส่วนโดยที่แต่ละส่วนมีส่วนของตัวเอง สัญญาณบอกสถานะการโหลด ซึ่งทำให้ผู้ใช้รู้สึกสะอิดสะเอียนมากขึ้น

จัดการการโหลดที่ไม่สำเร็จ

Suspense ช่วยให้คุณแสดงสถานะการโหลดชั่วคราวในขณะที่เครือข่าย คําขอจะดำเนินการไว้เบื้องหลัง แต่จะเกิดอะไรขึ้นหากคำขอเครือข่ายเหล่านั้นล้มเหลว ด้วยเหตุผลบางประการ คุณอาจออฟไลน์อยู่ หรือเว็บแอปอาจกำลังพยายาม โหลด URL ที่มีเวอร์ชันแบบ Lazy Loading ที่ไม่อัปเดต และไม่มีอีกต่อไปหลังจากการติดตั้งใช้งานเซิร์ฟเวอร์ใหม่

React มีรูปแบบมาตรฐานสำหรับการจัดการกับการโหลดประเภทเหล่านี้อย่างราบรื่น ข้อผิดพลาด: ใช้ขอบเขตของข้อผิดพลาด ตามที่อธิบายไว้ในเอกสารประกอบ คอมโพเนนต์รีแอ็กชันใดๆ ทำหน้าที่เป็นขอบเขตข้อผิดพลาดได้หากดำเนินการอย่างใดอย่างหนึ่ง (หรือ ทั้งคู่) ของวิธีวงจร static getDerivedStateFromError() หรือ componentDidCatch()

หากต้องการตรวจหาและจัดการความล้มเหลวในการโหลดแบบ Lazy Loading คุณรวม 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. เริ่มต้นที่ระดับเส้นทาง เส้นทางเป็นวิธีที่ง่ายที่สุดในการระบุจุด แอปพลิเคชันของคุณที่แยกส่วนได้ แสดงความรู้สึกในเอกสาร แสดงวิธีใช้ Suspense ร่วมกับ react-router
  2. ระบุองค์ประกอบขนาดใหญ่บนหน้าบนเว็บไซต์ที่แสดงผลเฉพาะบน การโต้ตอบบางอย่างของผู้ใช้ (เช่น การคลิกปุ่ม) แยกส่วนเหล่านี้ จะทำให้เพย์โหลด JavaScript ลดลง
  3. ลองแยกส่วนเนื้อหาอื่นๆ ที่ไม่อยู่ในหน้าจอและไม่สำคัญสำหรับ ผู้ใช้