הקסם של Suspense בריאקט

27/05/2024

הרבה זמן היה קשה לראות את זה, אבל עכשיו עם Server Components הקומפוננטה Suspense מקבלת כח חדש והופכת להכרחית בהרבה אפליקציות next.js. הסיפור הולך כך:

  1. יש לנו עמוד עם חלקים שונים שזמן הטעינה שלהם שונה - לדוגמה אזור תוכן מרכזי שמגיע מהר מהזיכרון או קבצים, כתבות ארוכות יותר שמגיעות מקריאה לבסיס נתונים ואזור צד שמגיע מקריאה ל API צד שלישי (שרת לשרת).

  2. אנחנו רוצים לשלוח ללקוח את העמוד כמה שיותר מהר, וכשיגיעו הנתונים מבסיס הנתונים או מה API "להשלים" אותם בעמוד.

בעבר הדרך היחידה לעשות את זה היתה מתוך קוד צד לקוח - אנחנו מקבלים את העמוד ואז JavaScript בצד לקוח פונה לשרת ומתחיל שתי בקשות רשת חדשות עבור המידע מבסיס הנתונים והמידע מה API צד-שלישי. כל בקשה תחזור בזמן שלה והתוכן יוצג כשהתוצאות יגיעו. החיסרון במנגנון הזה הוא שאנחנו צריכים לחכות שהדפדפן יטען את אפליקציית הריאקט, ישלח הודעות חדשות לשרת ורק אז השרת פונה למשוך את המידע הנוסף שצריך. בנוסף (וזו סתם תכונה מעצבנת של ריאקט), אנחנו צריכים להתמודד בצד לקוח עם מצב של קומפוננטה שנמצאת במצב טעינה ולהציג תוכן חלופי בקוד הקומפוננטה.

הפונקציה use שתיכנס בריאקט 19 תאפשר לשפר קצת את המצב מבחינת אפליקציית צד הלקוח בכך שנוכל לעצור את הרינדור באמצע ולחכות ל Promise (קצת כמו await באמצע קוד קומפוננטה), ואז לא נצטרך לטפל במצב שהקומפוננטה "טוענת". מנגנון Server Components וה Component Streaming מאפשר ללכת עוד צעד קדימה ולטפל בכל הסיפור הזה בצד השרת.

שימו לב לדוגמה הבאה:

import { Suspense } from 'react'; 

/* We've moved data fetching into the changlog compoment */
async function ChangelogWithDataFetching() {
  const changelogData = await getChangelogData()
  return <Changelog data={changelogData} />
}

/*
  ...and wrapped that component in Suspense.
  The user can see the page immediately, while the changelog component loads
*/
export default function Page() {
  return (
    <Layout>
      <Sidebar>
        {/* other sidebar stuff */}
        <Suspense fallback={<ChangelogPlaceholder />}>
          <ChangelogWithDataFetching />
        </Suspense>
      </Sidebar>
      {/* other page stuff */}
    </Layout>
  )
}

קוד הגיע מכאן.

יש להם את הקומפוננטה ChangelogWithDataFetching שבסך הכל מוסיפה קריאה לפונקציה אסינכרונית כדי למשוך מידע ואז מרנדרת את הקומפוננטה Changelog. המקום היחיד שיצטרך לדאוג לאיך הקומפוננטה נראית במצב טעינה זה הקומפוננטה ChangelogPlaceholder שמופיעה ב Suspense. הצעד הזה קדימה - גם בקומפוננטות צד שרת אבל גם תכף בקומפוננטות צד לקוח עם use - נותן ל Suspense כח על חדש ואני חושב שיגרום לנו להשתמש הרבה יותר בקומפוננטה זו.