đ§ React Suspense āĻāĻŋ, āĻā§āύ āĻāϏāϞ⧠(āĻŦāĻŋāϏā§āϤāĻžāϰāĻŋāϤ)
āϧāϰā§āύ, āĻāĻĒāύāĻŋ āĻāĻāĻāύ React āĻĄā§āĻā§āϞāĻĒāĻžāϰāĨ¤ āĻāĻāĻāĻžāϰ āĻāύā§āĻāĻžāϰāĻĢā§āϏ āĻŦāĻžāύāĻžāĻā§āĻā§āύ āĻāϰ āĻāĻĒāύāĻžāϰ āĻĻāϰāĻāĻžāϰâāĻā§āύ⧠āĻāĻāĻāĻž āĻāĻŽā§āĻĒā§āύā§āύā§āĻ āϤāĻāύāĻ āĻĻā§āĻāĻžāύ⧠āĻšāĻŦā§, āϝāĻāύ āĻĄā§āĻāĻž āϰā§āĻĄāĻŋ āĻšāĻŦā§āĨ¤
āĻāĻāϰāĻāĻŽ āϏāĻŽā§ā§, āĻāĻā§āϰ āĻŽāϤ⧠useState āĻāϰ useEffect āĻĻāĻŋā§ā§ āϞā§āĻĄāĻŋāĻ āĻŽā§āϝāĻžāύā§āĻ āĻāϰāĻž āϝāĻžā§ āĻ āĻŋāĻāĻâbut āĻāĻžāĻŽā§āϞāĻž āĻšā§ āϝāĻāύ āĻ
āύā§āĻāĻā§āϞ⧠āĻāĻžā§āĻāĻžā§ āĻāĻāϏāĻžāĻĨā§ āϞā§āĻĄāĻŋāĻ/āĻāϰāϰ āĻšā§āϝāĻžāύā§āĻĄā§āϞ āĻāϰāϤ⧠āĻšā§āĨ¤
React Suspense āĻāϏāĻā§ āĻāĻ āϏāĻŽāϏā§āϝāĻžāϰ āϏāĻŽāĻžāϧāĻžāύā§āĨ¤
đ Suspense āĻāĻŋ?
<Suspense> āĻāϏāϞ⧠āĻāĻāĻāĻž React āĻāĻŽā§āĻĒā§āύā§āύā§āĻ, āϝā§āĻāĻž āĻ
āύā§āϝ āĻā§āύ⧠āĻāĻŽā§āĻĒā§āύā§āύā§āĻāĻā§ âāϧāϰā§â āϰāĻžāĻā§ āϝāϤāĻā§āώāĻŖ āύāĻž āϏā§āĻāĻž āĻĒā§āϰ⧠āϰā§āύā§āĻĄāĻžāϰ āĻāϰāĻžāϰ āĻāύā§āϝ āĻĒā§āϰāϏā§āϤā§āϤāĨ¤
đĻ āϏāĻšāĻ āĻāĻžāώāĻžā§:
<Suspense fallback={<Loading />}>
<Albums />
</Suspense>āĻāĻ āĻā§āĻĄā§, āϝāĻĻāĻŋ Albums āĻāĻŽā§āĻĒā§āύā§āύā§āĻā§āϰ āĻā§āϤāϰ⧠āĻĄā§āĻāĻž āĻĢā§āĻ āĻāϰāϤ⧠āĻāĻŋā§ā§ "āϏāĻŽā§ āϞāĻžāĻā§", āϤāĻāύ Suspense Loading āĻĻā§āĻāĻžāĻŦā§āĨ¤
đ¤ Suspense āĻāĻŋāĻāĻžāĻŦā§ āĻāĻžāĻ āĻāϰā§?
āϧāϰā§āύ āĻāĻāĻāĻž āĻāĻŽā§āĻĒā§āύā§āύā§āĻ āϰā§āύā§āĻĄāĻžāϰ āĻšāĻā§āĻā§, āĻšāĻ āĻžā§ āϤāĻžāϰ āĻŽāϧā§āϝ⧠āĻĄā§āĻāĻž āĻĻāϰāĻāĻžāϰ āĻĒā§āϞā§, āĻāϰ āϏā§āĻ āĻĄā§āĻāĻž āĻāϏāĻž āĻĒāϰā§āϝāύā§āϤ āĻ āĻĒā§āĻā§āώāĻž āĻāϰāϤ⧠āĻšāĻŦā§āĨ¤
āϤāĻāύ āĻā§ āĻšā§?
- āĻĒā§āϰāĻĨāĻŽāϤ āĻ āĻāĻŽā§āĻĒā§āύā§āύā§āĻāĻāĻŋ āĻŽā§āϞ JSX Return āĻāϰāĻŦā§ āύāĻž, āĻāĻāĻāĻž Promise āĻĨā§āϰ⧠āĻāϰā§āĨ¤
- React āĻĻā§āĻā§, âāĻāĻš! Suspense āĻāĻā§ āĻāĻžāĻā§āĻ?â â āϝāĻĻāĻŋ āĻĨāĻžāĻā§, āϏā§āĻāĻž fallback UI (āϝā§āĻŽāύ Loading spinner) āĻĻā§āĻāĻžāϤ⧠āĻļā§āϰ⧠āĻāϰā§āĨ¤ āϝāϤāĻā§āώāĻŖ āύāĻž Promise āϰā§āĻāϞāĻ āĻšā§āĨ¤
- Promise resolve āĻšāϞā§āĻ āĻāϏāϞ āĻāĻŽā§āĻĒā§āύā§āύā§āĻ (JSX) āϰā§āύā§āĻĄāĻžāϰ āĻšā§āĨ¤
Implmentation Suspense (āĻāϞā§āύ āĻŦāĻžāϏā§āϤāĻŦ āĻāĻĻāĻžāĻšāϰāĻŖ āĻĻā§āĻāĻŋ)
Option 1: wrapPromise() āĻŽā§āϝāĻžāύā§ā§āĻžāϞāĻŋ āϞāĻŋāĻā§ āĻĢā§āϞā§
React āĻ use() āĻšā§āĻ āĻāϏāĻžāϰ āĻāĻā§ Suspense āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰāϤ⧠āĻāĻžāĻāϞ⧠āĻāĻŽāĻžāĻĻā§āϰ wrapperPromise āĻŦāĻž resource.read() āϧāϰāύā§āϰ āĻŽā§āϝāĻžāύā§ā§āĻžāϞ Promise handling utility āϞāĻŋāĻāϤ⧠āĻšāϤā§āĨ¤ āĻāĻāĻž āĻŦā§āĻāĻžāύ⧠āĻĻāϰāĻāĻžāϰ, āϝā§āύ āĻĒāĻžāĻ āĻ āĻŦā§āĻāϤ⧠āĻĒāĻžāϰā§āύ āĻāĻŋāĻāĻžāĻŦā§ Suspense āĻāϰ āϧāĻžāϰāĻŖāĻž āĻāϏā§āĻā§ āĻāĻŦāĻ āĻāĻā§āĻ āĻāĻāĻž āĻāĻŋāĻāĻžāĻŦā§ āĻāĻžāĻ āĻāϰāϤāĨ¤
āĻāĻā§ āĻāĻŽāϰāĻž wrapPromise āύāĻŋā§ā§ āĻāϞā§āĻāύāĻž āĻāϰāĻŦ, āϤāĻžāϰāĻĒāϰ āĻĻā§āĻāĻžāĻŦ āĻāĻŋāĻāĻžāĻŦā§ use() āĻāϏ⧠āϏāĻŦ āϏāĻšāĻ āĻāϰ⧠āĻĻāĻŋāϞā§āĨ¤ āϏā§āĻāϏāĻžāĻĨā§ āĻŦā§āĻāĻžāύ⧠āĻšāĻŦā§ āĻāĻ āĻĒāϰāĻŋāĻŦāϰā§āϤāύ āĻā§āύ āĻā§āϰā§āϤā§āĻŦāĻĒā§āϰā§āĻŖāĨ¤
āϧāϰā§āύ, āĻāĻĒāύāĻžāϰ āĻāĻāĻāĻž āĻāĻŽā§āĻĒā§āύā§āύā§āĻ āĻāĻā§, āϝā§āĻāĻž API āĻĨā§āĻā§ āĻĄā§āĻāĻž āĻāύāĻŦā§āĨ¤ āĻāĻĒāύāĻŋ āĻāĻžāύ, āϝāϤāĻā§āώāĻŖ āύāĻž āĻĄā§āĻāĻž āĻāϏā§, āϤāϤāĻā§āώāĻŖ āĻāĻāĻāĻž ââŗ LoadingâĻâ āĻĻā§āĻāĻž āϝāĻžāĻŦā§āĨ¤
āĻāĻā§ (āĻŽāĻžāύ⧠<Suspense/> āĻāϏāĻžāϰ āĻāĻ āĻĒāϰā§āϝāύā§āϤ) āĻāĻĒāύāĻŋ āĻā§āĻāĻžāĻŦā§ āĻāϰāϤā§āύ?
âī¸ useState + useEffect
const [albums, setAlbums] = useState(null);
useEffect(() => {
fetch("/albums")
.then((res) => res.json())
.then((data) => setAlbums(data));
}, []);āĻāϰ āϏāĻžāĻĨā§ āĻāĻāĻāĻž isLoading, āĻāĻāĻāĻž error state āϰāĻžāĻāϤ⧠āĻšāϤā§āĨ¤ āĻāĻāĻž āĻā§āĻ āĻ
ā§āϝāĻžāĻĒā§ āĻāϞāϤ, āĻāĻŋāύā§āϤ⧠āĻāĻāĻŋāϞ āĻ
ā§āϝāĻžāĻĒā§ āĻā§āĻĄ āĻšāϤ⧠āĻŦāĻŋāĻļā§āϰā§āĨ¤
đ āϤāĻāύ React Suspense āĻāϏāϞā§â āĻāĻŋāύā§āϤ⧠āĻāĻāĻāĻŋ āϏāĻŽāϏā§āϝāĻž
React āϤāĻāύ āĻŦāϞāϞā§:
âāϤā§āĻŽāĻŋ āĻāĻžāĻāϞ⧠āĻāĻāύ āĻāĻŽā§āĻĒā§āύā§āύā§āĻāĻā§ āϰā§āύā§āĻĄāĻžāϰ āĻšāϤ⧠āĻĨāĻžāĻŽāĻŋā§ā§ āĻĻāĻŋāϤ⧠āĻĒāĻžāϰā§, āϝāϤāĻā§āώāĻŖ āύāĻž āĻĄā§āĻāĻž āĻāϏā§āĨ¤â
function wrapPromise(promise) {
let status = "pending";
let result;
const suspender = promise.then(
(res) => {
status = "success";
result = res;
},
(err) => {
status = "error";
result = err;
}
);
return {
read() {
if (status === "pending") {
throw suspender;
} else if (status === "error") {
throw result;
} else {
return result;
}
},
};
}đ¯ āĻā§āĻĄā§ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰāĻŋ āĻāĻāύ
// data.js
function fetchAlbums() {
return fetch("/albums").then((res) => res.json());
}
const albumResource = wrapPromise(fetchAlbums());// Albums.js
function Albums() {
const albums = albumResource.read(); // āĻāĻāĻžāύ⧠Suspense āĻāĻžāĻ āĻāϰā§
return (
<ul>
{albums.map((a) => (
<li key={a.id}>{a.title}</li>
))}
</ul>
);
}<Suspense fallback={<Loading />}>
 <Albums />
</Suspense>â wrapperPromise() āϏāĻŽāϏā§āϝāĻž āĻā§?
wrapPromise()āύāĻŋāĻā§ āϞāĻŋāĻāϤ⧠āĻšāϤā§- āĻāύāϏāĻŋāϏā§āĻā§āύā§āĻ error boundary āĻšā§āϝāĻžāύā§āĻĄāϞāĻŋāĻ āĻāĻ āĻŋāύ āĻāĻŋāϞ
- Boilerplate āĻ āύā§āĻ
đ¯ React 18 āĻĨā§āĻā§ āĻāĻāĻž āĻ
āύā§āĻ āϏāĻšāĻ āĻšā§ā§āĻā§ āĻāĻžāϰāĻŖ āĻāĻāύ use() āύāĻžāĻŽā§āϰ āĻšā§āĻ āĻāĻā§āĨ¤
Option 2: use() āĻšā§āĻ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰā§
ā§§. Data fetch āĻāϰāĻžāϰ āĻĢāĻžāĻāĻļāύ
// data.js
let cache = new Map();
export function fetchData(url) {
if (!cache.has(url)) {
cache.set(url, getData(url));
}
return cache.get(url);
}
async function getData(url) {
await new Promise((resolve) => setTimeout(resolve, 2000)); // āĻĻā§āϰāĻŋ āĻāϰā§
const response = await fetch(url);
return await response.json();
}⧍. Albums āĻāĻŽā§āĻĒā§āύā§āύā§āĻ (Data fetch āĻāϰā§)
// Albums.js
import { use } from "react";
import { fetchData } from "./data.js";
export default function Albums() {
const albums = use(fetchData("https://jsonplaceholder.typicode.com/albums"));
return (
<ul>
{albums.slice(0, 5).map((album) => (
<li key={album.id}>{album.title}</li>
))}
</ul>
);
}â ī¸ āĻāĻāĻžāύ⧠āĻāĻŋāύā§āϤ⧠useEffect, useState āĻāĻŋāĻā§āĻ āύāĻžāĻ! āĻļā§āϧā§āĻ use() āĻšā§āĻ āĻāĻŦāĻ āĻāĻāĻž āύāĻŋāĻā§ āĻŦā§āĻā§ āύāĻŋāĻā§āĻā§ āĻāĻāύ fallback āĻĻā§āĻāĻžāĻŦā§āĨ¤
ā§Š. App.js - Suspense āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰā§
// App.js
import { Suspense } from "react";
import Albums from "./Albums.js";
function Loading() {
return <h2>âŗ Loading Albums...</h2>;
}
export default function App() {
return (
<div>
<h1>My Music App</h1>
<Suspense fallback={<Loading />}>
<Albums />
</Suspense>
</div>
);
}đ§ āĻāĻāύ āϝāĻĻāĻŋ Albums āĻĢā§āĻāĻŋāĻā§ā§ āϏāĻŽā§ āύā§ā§, āϤāĻāύ Loading āĻĻā§āĻāĻžāĻŦā§, āĻāϰ āĻĄā§āĻāĻž āĻāϞ⧠āĻāϏāϞ⧠Albums āϰā§āύā§āĻĄāĻžāϰ āĻšāĻŦā§āĨ¤
âī¸ āϝāĻĻāĻŋ āĻāĻŋāĻā§ Error āĻšā§?
React Suspense āύāĻŋāĻā§ āĻĨā§āĻā§ āĻāϰāϰ āĻšā§āϝāĻžāύā§āĻĄā§āϞ āĻāϰāϤ⧠āĻĒāĻžāϰ⧠āύāĻžāĨ¤ āĻāĻāύā§āϝ āĻĻāϰāĻāĻžāϰ ErrorBoundaryāĨ¤ āĻāĻāĻāύā§āϝ āĻāĻŽāϰāĻž āĻāĻāĻāĻž ErrorBoundary npm āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰāϤ⧠āĻĒāĻžāϰāĻŋ, āϝāĻž Suspense āĻāϰāϰ āĻšā§āϝāĻžāύā§āĻĄā§āϞ āĻāϰāĻŦā§āĨ¤ āĻāĻžāĻāϞ⧠āύāĻŋāĻā§āϰ āĻā§āĻĄāĻāĻŋāĻ āĻŦā§āϝāĻŦāĻšāĻžāϰ āĻāϰāϤ⧠āĻĒāĻžāϰāĻŋ,
// ErrorBoundary.js
import React from "react";
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false, error: null };
}
static getDerivedStateFromError(error) {
return { hasError: true, error };
}
render() {
if (this.state.hasError) {
return <h2>â {this.state.error.message}</h2>;
}
return this.props.children;
}
}
export default ErrorBoundary;āĻāĻāύ App.js āĻ āϰâā§āϝāĻžāĻĒ āĻāϰā§āύ:
import ErrorBoundary from "./ErrorBoundary.js";
<ErrorBoundary>
<Suspense fallback={<Loading />}>
<Albums />
</Suspense>
</ErrorBoundary>;đ§Ŧ Nested Suspense â Step by Step Loading
React-āĻ āĻāĻĒāύāĻŋ āĻāĻžāĻāϞ⧠āĻāĻāĻāĻž āĻŦā§ UI āĻā§ āϧāĻžāĻĒā§ āϧāĻžāĻĒā§ āϞā§āĻĄ āĻāϰāϤ⧠āĻĒāĻžāϰā§āύāĨ¤
<Suspense fallback={<BigSpinner />}>
<Biography />
<Suspense fallback={<AlbumsGlimmer />}>
<Albums />
</Suspense>
</Suspense>đ āĻāĻāĻž āĻā§āĻāĻžāĻŦā§ āĻāĻžāĻ āĻāϰā§?
- Biography āύāĻž āĻāϏāĻž āĻĒāϰā§āϝāύā§āϤ â BigSpinner āĻĻā§āĻāĻžāĻŦā§
- Biography āĻāϞ⧠āĻāϞ⧠â Biography āĻĻā§āĻāĻžāĻŦā§
- Albums āĻāĻāύ⧠āύāĻž āĻāϞ⧠â AlbumsGlimmer āĻĻā§āĻāĻžāĻŦā§
- Albums āĻāϏāϞ⧠â āĻĒā§āϰāĻž UI ready
đ§ŧ āϏāĻžāϰāĻžāĻāĻļ â āĻā§ āĻļāĻŋāĻāϞāĻžāĻŽ?
| āĻļāĻŋāĻā§āĻāĻŋ | āĻ āϰā§āĻĨ |
|---|---|
<Suspense fallback={...}> | āϞā§āĻĄāĻŋāĻ UI āĻĻā§āĻāĻžāϤ⧠āϏāĻžāĻšāĻžāϝā§āϝ āĻāϰ⧠|
use() | āĻĄā§āĻāĻž āϞā§āĻĄ āĻšā§ā§ āĻā§āϞ⧠āϰāĻŋāĻāĻžāϰā§āύ, āύāĻž āĻšāϞ⧠suspend āĻāϰ⧠|
| Nested Suspense | UI āϧāĻžāĻĒā§ āϧāĻžāĻĒā§ āĻĻā§āĻāĻžāύ⧠āϝāĻžā§ |
| ErrorBoundary | āĻāϰāϰ āϧāϰāϤ⧠āϞāĻžāĻā§ |
startTransition | UI āĻā§āϰāĻžāύāĻāĻŋāĻļāύ āϏā§āĻŽā§āĻĨ āϰāĻžāĻā§ |
đ Bonus Tip
React Suspense āĻāĻāύ⧠evolving, āϤāĻžāĻ āϏāĻŦ āĻĄā§āĻāĻž āĻĢā§āĻāĻŋāĻ āϞāĻžāĻāĻŦā§āϰā§āϰāĻŋ (āϝā§āĻŽāύ Axios) āϏāϰāĻžāϏāϰāĻŋ āϏāĻžāĻĒā§āϰā§āĻ āĻāϰ⧠āύāĻžāĨ¤ āϤāĻŦā§ Next.js āĻŦāĻž Relay āĻāϰ āĻŽāϤ⧠āĻĢā§āϰā§āĻŽāĻā§āĻžāϰā§āĻā§ Suspense āĻā§āĻŦ āĻāĻžāϞ⧠āĻāĻžāĻ āĻāϰā§āĨ¤