Join the discussion
Comments
Loading comments...
Cookie preferences
We use essential cookies for sign-in and preferences. With your permission, we also use basic analytics to improve lessons.
Join the discussion
Loading comments...
We use essential cookies for sign-in and preferences. With your permission, we also use basic analytics to improve lessons.
Rendu de secours, division de code et SSR en streaming avec les limites Suspense.
Suspense est un mécanisme qui permet aux composants d'attendre quelque chose avant de se rendre. Lorsqu'un composant n'est pas prêt (un import lazy n'a pas chargé, ou une récupération de données n'a pas résolu), il lève une Promise. React capture cette Promise levée, trouve la limite Suspense la plus proche dans l'arbre, affiche son interface de secours et re-rend automatiquement le sous-arbre lorsque la Promise se résout.
React.lazy(() => import('./MonComposant')) enveloppe un import dynamique dans un wrapper spécial. La première fois que React essaie de le rendre, l'import() n'a pas encore résolu, donc le wrapper lazy lève une Promise.
Pendant la phase de rendu, React capture les Promises levées (pas les Errors — celles-ci vont aux Limites d'Erreur). Il remonte dans l'arbre Fiber pour trouver l'ancêtre <Suspense> le plus proche et rend sa prop fallback au lieu du sous-arbre suspendu.
React attache un gestionnaire .then() à la Promise levée. Lorsque la Promise se résout (le module charge, ou les données arrivent), React re-rend le sous-arbre suspendu depuis le début, en utilisant cette fois la valeur résolue.
En mode concurrent, React peut 'essayer' de rendre un sous-arbre suspendu sans le commiter dans le DOM. S'il se suspend, React continue d'afficher l'ancien contenu (pas de flash vers le secours) jusqu'à ce que la Promise se résolve, puis permute vers le nouveau contenu de manière atomique.
Avec le streaming Next.js/React 18, le serveur envoie immédiatement le shell HTML avec les interfaces de secours Suspense en place. Au fur et à mesure que chaque récupération de données asynchrone se résout sur le serveur, React diffuse le morceau HTML rempli vers le navigateur, remplaçant le secours en ligne.
Enveloppe un import dynamique pour créer un composant chargé paresseusement. Au premier rendu, lève une Promise. À la résolution, React re-rend avec le module chargé.
<Suspense fallback='{'<Spinner/>'}'> capture les Promises levées depuis n'importe quel descendant. Affiche le secours pendant l'attente, révèle les enfants lorsqu'ils sont prêts.
Le mécanisme par lequel les composants signalent qu'ils ne sont pas prêts. N'importe quel composant (pas seulement les lazy) peut lever une Promise pour déclencher Suspense — c'est ainsi que les bibliothèques de récupération de données comme React Query s'intègrent.
Le serveur envoie le HTML progressivement. Le shell se rend immédiatement avec les interfaces de secours. Au fur et à mesure que le travail asynchrone se termine, React diffuse des morceaux de contenu remplis vers le navigateur.
Coordonne l'ordre de révélation de plusieurs limites Suspense. Peut imposer 'together' (révéler tout d'un coup) ou 'forwards'/'backwards' (révéler dans l'ordre).
1// Code splitting with React.lazy2const HeavyChart = React.lazy(() => import('./HeavyChart'));34function App() {5 return (6 <Suspense fallback={<Spinner />}>7 <HeavyChart /> {/* loads the JS bundle on demand */}8 </Suspense>9 );10}1112// Data fetching (with a Suspense-compatible library)13// The library throws a Promise internally when data isn't ready14function UserProfile({ userId }) {15 // use() hook (React 19) or library wrapper throws if not ready16 const user = use(fetchUser(userId));17 return <h1>{user.name}</h1>;18}1920<Suspense fallback={<ProfileSkeleton />}>21 <UserProfile userId={1} />22</Suspense>
Suspense unifie trois problèmes auparavant séparés — découpage de code, états de chargement et streaming serveur — sous un seul modèle déclaratif. Au lieu de suivre les indicateurs isLoading dans chaque composant, vous déclarez une limite et un secours, et React gère l'orchestration. Cela conduit à un code de récupération de données considérablement plus simple et élimine les bugs de gestion d'état de chargement.
Your SPA ships a 2MB JavaScript bundle. The landing page only needs 200KB of it — the rest is for the admin panel, chart library, and markdown editor that 80% of users never visit.
Without code splitting, the browser downloads, parses, and executes 2MB of JavaScript before showing anything. On mobile (3G network + slower CPU), this means 8+ seconds before the page is interactive — most users bounce.
Use `React.lazy` + `Suspense` at route boundaries: `const AdminPanel = React.lazy(() => import('./AdminPanel'))`. The initial bundle drops to 200KB. When a user navigates to /admin, the AdminPanel chunk loads on demand. The Suspense fallback shows a skeleton while the chunk downloads.
Takeaway: Code splitting at route boundaries is the highest-impact optimization for initial load time. Wrap lazy-loaded routes in Suspense with skeleton fallbacks. Tools like Next.js do this automatically for page components, but you should also lazy-load heavy feature components within pages.
A dashboard page loads 3 things: sidebar navigation (fast), main content (medium), and analytics charts (slow). With a single Suspense boundary, the entire page shows a spinner until the slowest component (charts) finishes loading.
One Suspense boundary at the page level means the entire page is either 'loading' or 'ready'. The sidebar (50ms) and main content (200ms) are ready quickly, but the user stares at a full-page spinner for 2 seconds waiting for the charts.
Nest multiple Suspense boundaries: one around the sidebar (shows instantly), one around the main content (shows after 200ms), one around the charts (shows after 2s). Each section renders independently as its data/code becomes available. The page progressively reveals content instead of all-or-nothing.
Takeaway: Use nested Suspense boundaries to control loading granularity. The boundary placement determines the loading UX: coarse boundaries (page-level) show everything at once, fine boundaries (component-level) enable progressive, streaming-style loading.