คุณไม่จำเป็นต้องจัดส่งโค้ดเกินกว่าที่จำเป็นไปยังผู้ใช้ ดังนั้นให้แยกแพ็กเกจของคุณเพื่อให้แน่ใจว่าปัญหาจะไม่เกิดขึ้น
เมธอด React.lazy
ช่วยให้คุณแยกโค้ดแอปพลิเคชัน React ในระดับคอมโพเนนต์ได้อย่างง่ายดายโดยใช้การนําเข้าแบบไดนามิก
import React, { lazy } from 'react';
const AvatarComponent = lazy(() => import('./AvatarComponent'));
const DetailsComponent = () => (
<div>
<AvatarComponent />
</div>
)
มีประโยชน์อย่างไร
แอปพลิเคชัน React ขนาดใหญ่มักจะประกอบด้วยคอมโพเนนต์มากมาย วิธีการของยูทิลิตี และไลบรารีของบุคคลที่สาม หากคุณไม่ได้พยายามโหลดส่วนต่างๆ ของแอปพลิเคชันเฉพาะเมื่อจำเป็นเท่านั้น ระบบจะส่ง JavaScript 1 กลุ่มไปยังผู้ใช้ของคุณทันทีที่โหลดหน้าเว็บหน้าแรก ซึ่งอาจส่งผลต่อประสิทธิภาพของหน้าเว็บอย่างมาก
ฟังก์ชัน 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
เป็นกลุ่มแยกกัน
การระงับคอมโพเนนต์หลายรายการ
อีกฟีเจอร์หนึ่งของ 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 เวอร์ชันที่ล้าสมัยและไม่พร้อมใช้งานอีกต่อไปหลังจากการทำให้เซิร์ฟเวอร์ใช้งานได้อีกครั้ง
React มีรูปแบบมาตรฐานในการจัดการข้อผิดพลาดในการโหลดเหล่านี้อย่างมีชั้นเชิง ซึ่งก็คือการใช้ขอบเขตข้อผิดพลาด ตามที่อธิบายไว้ในเอกสารประกอบ คอมโพเนนต์ React ใดก็ตามอาจทำหน้าที่เป็นขอบเขตข้อผิดพลาดได้หากคอมโพเนนต์ดังกล่าวใช้วิธีการอย่างใดอย่างหนึ่ง (หรือทั้ง 2 อย่าง) สำหรับวงจร 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 ของคุณที่ไหน ให้ทำตามขั้นตอนต่อไปนี้
- เริ่มต้นที่ระดับเส้นทาง เส้นทางเป็นวิธีที่ง่ายที่สุดในการระบุจุดของแอปพลิเคชันที่แยกได้ ส่วนเอกสารแสดงความรู้สึกจะแสดงวิธีใช้
Suspense
ร่วมกับreact-router
- ระบุคอมโพเนนต์ขนาดใหญ่บนหน้าเว็บบนไซต์ที่จะแสดงผลเฉพาะการโต้ตอบของผู้ใช้บางอย่าง (เช่น การคลิกปุ่ม) การแยกคอมโพเนนต์เหล่านี้จะลดเพย์โหลด JavaScript
- พิจารณาแยกส่วนสิ่งที่อยู่นอกหน้าจอและไม่จำเป็นต่อผู้ใช้