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.
Suspense boundaries ke saath fallback rendering, code splitting aur streaming SSR.
Suspense ek mechanism hai jo components ko render hone se pehle kuch 'wait' karne deta hai. Jab ek component ready nahi hota (lazy import load nahi hua, ya data fetch resolve nahi hua), woh ek Promise throw karta hai. React is thrown Promise ko pakadta hai, tree mein upar nearest Suspense boundary dhundhta hai, uski fallback UI dikhata hai, aur Promise resolve hone par subtree ko automatically re-render karta hai.
React.lazy(() => import('./MyComponent')) ek dynamic import ko ek special wrapper mein wrap karta hai. Jab pehli baar React ise render karne ki koshish karta hai, toh import() abhi resolve nahi hua hota, isliye lazy wrapper ek Promise throw karta hai.
Render phase ke dauran, React thrown Promises pakadta hai (thrown Errors nahi â woh Error Boundaries tak jaate hain). Woh fiber tree mein upar traverse karke nearest <Suspense> ancestor dhundhta hai aur suspended subtree ki jagah uska fallback prop render karta hai.
React thrown Promise par ek .then() handler attach karta hai. Jab Promise resolve hota hai (module load hota hai, ya data aata hai), React suspended subtree ko scratch se re-render karta hai, is baar resolved value use karke.
Concurrent mode mein, React ek suspended subtree ko DOM mein commit kiye bina 'try' kar sakta hai render karne ki. Agar woh suspend karta hai, React purana content dikhata rehta hai (fallback par flash nahi) jab tak Promise resolve nahi ho jaata, phir nayi content atomically swap ho jaati hai.
Next.js/React 18 streaming ke saath, server turant HTML shell bhejta hai jisme Suspense fallbacks hote hain. Jaise-jaise server par har async data fetch resolve hota hai, React filled-in HTML chunk browser tak stream karta hai, fallback ko inline replace karte hue.
Ek dynamic import ko wrap karke lazily-loaded component banata hai. Pehle render par, ek Promise throw karta hai. Resolution par, React loaded module ke saath re-render karta hai.
<Suspense fallback='{'<Spinner/>'}'> kisi bhi descendant se thrown Promises pakadta hai. Wait karte waqt fallback dikhata hai, ready hone par children reveal karta hai.
Woh mechanism jisse components signal karte hain ki woh ready nahi hain. Koi bhi component (sirf lazy wale nahi) Suspense trigger karne ke liye ek Promise throw kar sakta hai â aise hi data-fetching libraries jaise React Query integrate hoti hain.
Server HTML progressively bhejta hai. Shell turant fallbacks ke saath render hoti hai. Jaise async kaam complete hota hai, React filled content chunks browser ko stream karta hai.
Multiple Suspense boundaries ke reveal order ko coordinate karta hai. 'Together' (ek saath reveal) ya 'forwards'/'backwards' (order mein reveal) enforce kar sakta hai.
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 teen pehle se alag problems â code splitting, loading states, aur server streaming â ko ek declarative model ke neeche ekjut karta hai. Har component mein isLoading flags track karne ki jagah, aap ek boundary aur fallback declare karte hain, aur React orchestration handle karta hai. Isse data-fetching code kaafi simple hota hai aur loading state management bugs khatam ho jaate hain.
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.