lazy מאפשרת לדחות טעינה של קוד קומפוננטה עד לרינדור הראשון שלה.

const SomeComponent = lazy(load)

Reference

lazy(load)

קראו ל-lazy מחוץ לקומפוננטות שלכם כדי להצהיר על קומפוננטת React בטעינה עצלה:

import { lazy } from 'react';

const MarkdownPreview = lazy(() => import('./MarkdownPreview.js'));

ראו דוגמאות נוספות בהמשך.

Parameters

  • load: פונקציה שמחזירה Promise או thenable אחר (אובייקט דמוי Promise עם מתודת then). React לא תקרא ל-load עד הפעם הראשונה שבה תנסו לרנדר את הקומפוננטה המוחזרת. אחרי ש-React קוראת ל-load בפעם הראשונה, היא תחכה שהפונקציה תיפתר, ואז תרנדר את .default של הערך שנפתר כקומפוננטת React. גם ה-Promise המוחזר וגם הערך שנפתר ממנו יישמרו במטמון, כך ש-React לא תקרא ל-load יותר מפעם אחת. אם ה-Promise נדחה, React תבצע throw לסיבת הדחייה עבור Error Boundary הקרוב כדי שיטפל בה.

Returns

lazy מחזירה קומפוננטת React שאפשר לרנדר בעץ שלכם. בזמן שקוד הקומפוננטה העצלה עדיין נטען, ניסיון לרנדר אותה יגרום ל-suspend. השתמשו ב-<Suspense> כדי להציג אינדיקציית טעינה בזמן שהיא נטענת.


פונקציית load

Parameters

load לא מקבלת פרמטרים.

Returns

צריך להחזיר Promise או thenable אחר (אובייקט דמוי Promise עם מתודת then). בסופו של דבר היא צריכה להיפתר לאובייקט שהמאפיין .default שלו הוא סוג קומפוננטת React תקין, כמו פונקציה, קומפוננטת memo, או קומפוננטת forwardRef.


שימוש

טעינת קומפוננטות בעצלות עם Suspense

בדרך כלל מייבאים קומפוננטות באמצעות הצהרת import סטטית:

import MarkdownPreview from './MarkdownPreview.js';

כדי לדחות טעינה של קוד הקומפוננטה הזו עד לרינדור הראשון שלה, החליפו את הייבוא הזה ב:

import { lazy } from 'react';

const MarkdownPreview = lazy(() => import('./MarkdownPreview.js'));

הקוד הזה נשען על import() דינמי, שעשוי לדרוש תמיכה מה-bundler או מה-framework שלכם. שימוש בדפוס הזה דורש שהקומפוננטה העצלה שאתם מייבאים יוצאה כ-default export.

עכשיו, כשהקוד של הקומפוננטה נטען לפי דרישה, צריך גם לציין מה יוצג בזמן הטעינה. אפשר לעשות זאת על ידי עטיפת הקומפוננטה העצלה או אחד מההורים שלה בתוך גבול <Suspense>:

<Suspense fallback={<Loading />}>
<h2>Preview</h2>
<MarkdownPreview />
</Suspense>

בדוגמה הזו, הקוד של MarkdownPreview לא ייטען עד שתנסו לרנדר אותו. אם MarkdownPreview עדיין לא נטען, Loading יוצג במקומו. נסו לסמן את תיבת הסימון:

import { useState, Suspense, lazy } from 'react';
import Loading from './Loading.js';

const MarkdownPreview = lazy(() => delayForDemo(import('./MarkdownPreview.js')));

export default function MarkdownEditor() {
  const [showPreview, setShowPreview] = useState(false);
  const [markdown, setMarkdown] = useState('Hello, **world**!');
  return (
    <>
      <textarea value={markdown} onChange={e => setMarkdown(e.target.value)} />
      <label>
        <input type="checkbox" checked={showPreview} onChange={e => setShowPreview(e.target.checked)} />
        Show preview
      </label>
      <hr />
      {showPreview && (
        <Suspense fallback={<Loading />}>
          <h2>Preview</h2>
          <MarkdownPreview markdown={markdown} />
        </Suspense>
      )}
    </>
  );
}

// Add a fixed delay so you can see the loading state
function delayForDemo(promise) {
  return new Promise(resolve => {
    setTimeout(resolve, 2000);
  }).then(() => promise);
}

הדמו הזה נטען עם השהיה מלאכותית. בפעם הבאה שתבטלו ותסמנו שוב את תיבת הסימון, Preview כבר יהיה במטמון, ולכן לא יהיה מצב טעינה. כדי לראות שוב את מצב הטעינה, לחצו על “Reset” ב-sandbox.

קראו עוד על ניהול מצבי טעינה עם Suspense.


פתרון תקלות

ה-state של קומפוננטת lazy מתאפס באופן לא צפוי

אל תצהירו על קומפוננטות lazy בתוך קומפוננטות אחרות:

import { lazy } from 'react';

function Editor() {
// 🔴 Bad: This will cause all state to be reset on re-renders
const MarkdownPreview = lazy(() => import('./MarkdownPreview.js'));
// ...
}

במקום זאת, תמיד הצהירו עליהן ברמה העליונה של המודול:

import { lazy } from 'react';

// ✅ Good: Declare lazy components outside of your components
const MarkdownPreview = lazy(() => import('./MarkdownPreview.js'));

function Editor() {
// ...
}