เชี่ยวชาญกลไกการพักการเรนเดอร์ (suspension) การโหลดคอมโพเนนต์แบบ lazy และการแบ่งบันเดิล (bundle splitting)
เปิดบทเรียนนี้ใน KodokonSuspense อาศัยกลไกที่คนไม่ค่อยรู้จัก: คอมโพเนนต์ที่ยังไม่มีข้อมูลหรือโค้ดของมันจะ พัก (suspend) การเรนเดอร์ของตัวเอง เบื้องหลัง การนำไปใช้งานปัจจุบันจะโยน promise ออกมา ซึ่ง React ดักจับไว้เหมือนกับที่มันดักจับข้อผิดพลาด จากนั้น React จะไต่ขึ้นไปหา ขอบเขต <Suspense> ที่ใกล้ที่สุด แสดง fallback ของมัน แล้ว เล่นการเรนเดอร์ซ้ำ ของซับทรีเมื่อ promise คลี่คลาย (resolve) นี่เป็นรายละเอียดของการนำไปใช้งาน (อย่าโยน promise ด้วยตัวเองเด็ดขาด) แต่มันอธิบายพฤติกรรมที่สังเกตได้ทั้งหมด: ขอบเขตนี้ทำหน้าที่เหมือน catch แบบประกาศ (declarative) สำหรับงานแบบอะซิงโครนัส กรณีการใช้งานเชิงประวัติศาสตร์คือ code splitting ด้วย React.lazy
import { lazy, Suspense } from 'react';
const Chart = lazy(() => import('./Chart'));
function Dashboard() {
return (
<Suspense fallback={<Spinner />}>
<Chart points={data} />
</Suspense>
);
}lazy คาดหวังฟังก์ชันที่คืนค่า promise ซึ่งคลี่คลายไปเป็น โมดูลที่มี export เป็น default ตัวการแบ่ง (splitting) เองเป็นงานของบันเดิลเลอร์ (bundler): แต่ละ import() แบบไดนามิกจะกลายเป็นจุดแบ่ง (split point) และสร้าง ชังก์ (chunk) แยกต่างหาก ที่ถูกโหลดตามต้องการ ความละเอียดอ่อนที่พบบ่อยในโค้ดเบสจริง: คอมโพเนนต์ของคุณมักเป็น named export คุณจึงต้องปรับโมดูลในทันที (on the fly)
const Chart = lazy(() =>
import('./charts').then((module) => ({
default: module.Chart,
}))
);ส่วนที่ยุ่งยากในโปรดักชัน: ระหว่าง การนำทาง (navigation) เนื้อหาที่แสดงอยู่แล้วสามารถพักได้อีกครั้ง (เส้นทางใหม่ ชังก์ใหม่) และถูกแทนที่ด้วย fallback อย่างกะทันหัน ตั้งแต่ React 18 การอัปเดตที่ห่อไว้ใน startTransition จะเปลี่ยนพฤติกรรมนี้: React คงอินเทอร์เฟซเดิมไว้บนหน้าจอ ในขณะที่การเรนเดอร์ใหม่พักอยู่เบื้องหลัง และแสดง fallback เฉพาะกับเนื้อหาที่ไม่เคยถูกเปิดเผยมาก่อนเท่านั้น ขอบเขต (boundaries) ยังประกอบซ้อนกันในเชิงลึกได้อีกด้วย: ขอบเขต <Suspense> ที่ซ้อนกันหลายชั้นช่วยให้คุณเปิดเผยอินเทอร์เฟซทีละโซน ตั้งแต่โครงร่างระดับรวม (skeleton) ลงไปจนถึงรายละเอียด
const [isPending, startTransition] = useTransition();
function openTab(nextTab) {
startTransition(() => {
setTab(nextTab);
});
}
// The current tab stays visible while the new
// one loads, instead of dropping back to the fallback.React.lazy ต้องคืนค่าอะไร?