คุณไม่จำเป็นต้องส่งโค้ดมากเกินกว่าที่จำเป็นให้กับผู้ใช้ ดังนั้นให้แยกแพ็กเกจกันเพื่อไม่ให้เกิดปัญหานี้ขึ้น
เมธอด 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 (หรือ Command+Option+J ใน Mac) เพื่อเปิดเครื่องมือสำหรับนักพัฒนาซอฟต์แวร์
- คลิกแท็บเครือข่าย
- คลิกเมนูแบบเลื่อนลงการจำกัด ซึ่งตั้งค่าเป็นไม่มีการจำกัดโดยค่าเริ่มต้น เลือก Fast 3G
- คลิกปุ่มคลิกฉันในแอป
สัญญาณบอกสถานะการโหลดจะแสดงนานขึ้น โปรดสังเกตว่าระบบดึงข้อมูลโค้ดทั้งหมดที่ประกอบเป็น AvatarComponent
เป็นกลุ่มแยกต่างหาก
การระงับคอมโพเนนต์หลายรายการ
อีกฟีเจอร์หนึ่งของ 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 Load ซึ่งล้าสมัยและไม่พร้อมใช้งานอีกต่อไปหลังจากการนําเซิร์ฟเวอร์กลับมาใช้งานอีกครั้ง
React มีรูปแบบมาตรฐานในการจัดการการโหลดที่ไม่สําเร็จประเภทเหล่านี้อย่างราบรื่นโดยใช้ขอบเขตข้อผิดพลาด ตามที่อธิบายไว้ในเอกสารประกอบ คอมโพเนนต์ React ใดก็ตามทำหน้าที่เป็นขอบเขตข้อผิดพลาดได้ หากใช้วิธีอายุการใช้งาน static getDerivedStateFromError()
หรือ componentDidCatch()
(หรือทั้ง 2 อย่าง)
หากต้องการตรวจหาและจัดการการโหลดแบบเลื่อนเวลาไว้ทีหลังที่ไม่สําเร็จ คุณสามารถรวม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
- พิจารณาแยกเนื้อหาอื่นๆ ที่ไม่ได้แสดงบนหน้าจอและไม่สำคัญต่อผู้ใช้