📄 React Suspense

🧑 React Suspense āĻ•āĻŋ, āϕ⧇āύ āφāϏāϞ⧋ (āĻŦāĻŋāĻ¸ā§āϤāĻžāϰāĻŋāϤ)

āϧāϰ⧁āύ, āφāĻĒāύāĻŋ āĻāĻ•āϜāύ React āĻĄā§‡āϭ⧇āϞāĻĒāĻžāϰāĨ¤ āχāωāϜāĻžāϰ āχāĻ¨ā§āϟāĻžāϰāĻĢ⧇āϏ āĻŦāĻžāύāĻžāĻšā§āϛ⧇āύ āφāϰ āφāĻĒāύāĻžāϰ āĻĻāϰāĻ•āĻžāĻ°â€”āϕ⧋āύ⧋ āĻāĻ•āϟāĻž āĻ•āĻŽā§āĻĒā§‹āύ⧇āĻ¨ā§āϟ āϤāĻ–āύāχ āĻĻ⧇āĻ–āĻžāύ⧋ āĻšāĻŦ⧇, āϝāĻ–āύ āĻĄā§‡āϟāĻž āϰ⧇āĻĄāĻŋ āĻšāĻŦ⧇āĨ¤

āĻāχāϰāĻ•āĻŽ āϏāĻŽā§Ÿā§‡, āφāϗ⧇āϰ āĻŽāϤ⧋ useState āφāϰ useEffect āĻĻāĻŋā§Ÿā§‡ āϞ⧋āĻĄāĻŋāĻ‚ āĻŽā§āϝāĻžāύ⧇āϜ āĻ•āϰāĻž āϝāĻžā§Ÿ āĻ āĻŋāĻ•āĻ‡â€”but āĻāĻžāĻŽā§‡āϞāĻž āĻšā§Ÿ āϝāĻ–āύ āĻ…āύ⧇āĻ•āϗ⧁āϞ⧋ āϜāĻžā§ŸāĻ—āĻžā§Ÿ āĻāĻ•āϏāĻžāĻĨ⧇ āϞ⧋āĻĄāĻŋāĻ‚/āĻāϰāϰ āĻšā§āϝāĻžāĻ¨ā§āĻĄā§‡āϞ āĻ•āϰāϤ⧇ āĻšā§ŸāĨ¤

React Suspense āφāϏāϛ⧇ āĻāχ āϏāĻŽāĻ¸ā§āϝāĻžāϰ āϏāĻŽāĻžāϧāĻžāύ⧇āĨ¤


🔍 Suspense āĻ•āĻŋ?

<Suspense> āφāϏāϞ⧇ āĻāĻ•āϟāĻž React āĻ•āĻŽā§āĻĒā§‹āύ⧇āĻ¨ā§āϟ, āϝ⧇āϟāĻž āĻ…āĻ¨ā§āϝ āϕ⧋āύ⧋ āĻ•āĻŽā§āĻĒā§‹āύ⧇āĻ¨ā§āϟāϕ⧇ “āϧāĻ°ā§‡â€ āϰāĻžāϖ⧇ āϝāϤāĻ•ā§āώāĻŖ āύāĻž āϏ⧇āϟāĻž āĻĒ⧁āϰ⧋ āϰ⧇āĻ¨ā§āĻĄāĻžāϰ āĻ•āϰāĻžāϰ āϜāĻ¨ā§āϝ āĻĒā§āϰāĻ¸ā§āϤ⧁āϤāĨ¤

đŸ“Ļ āϏāĻšāϜ āĻ­āĻžāώāĻžā§Ÿ:

<Suspense fallback={<Loading />}>
  <Albums />
</Suspense>

āĻāχ āϕ⧋āĻĄā§‡, āϝāĻĻāĻŋ Albums āĻ•āĻŽā§āĻĒā§‹āύ⧇āĻ¨ā§āĻŸā§‡āϰ āϭ⧇āϤāϰ⧇ āĻĄā§‡āϟāĻž āĻĢ⧇āϚ āĻ•āϰāϤ⧇ āĻ—āĻŋā§Ÿā§‡ "āϏāĻŽā§Ÿ āϞāĻžāϗ⧇", āϤāĻ–āύ Suspense Loading āĻĻ⧇āĻ–āĻžāĻŦ⧇āĨ¤


🤔 Suspense āĻ•āĻŋāĻ­āĻžāĻŦ⧇ āĻ•āĻžāϜ āĻ•āϰ⧇?

āϧāϰ⧇āύ āĻāĻ•āϟāĻž āĻ•āĻŽā§āĻĒā§‹āύ⧇āĻ¨ā§āϟ āϰ⧇āĻ¨ā§āĻĄāĻžāϰ āĻšāĻšā§āϛ⧇, āĻšāĻ āĻžā§Ž āϤāĻžāϰ āĻŽāĻ§ā§āϝ⧇ āĻĄā§‡āϟāĻž āĻĻāϰāĻ•āĻžāϰ āĻĒ⧜āϞ⧋, āφāϰ āϏ⧇āχ āĻĄā§‡āϟāĻž āφāϏāĻž āĻĒāĻ°ā§āϝāĻ¨ā§āϤ āĻ…āĻĒ⧇āĻ•ā§āώāĻž āĻ•āϰāϤ⧇ āĻšāĻŦ⧇āĨ¤

āϤāĻ–āύ āϕ⧀ āĻšā§Ÿ?

  1. āĻĒā§āϰāĻĨāĻŽāϤ āϐ āĻ•āĻŽā§āĻĒā§‹āύ⧇āĻ¨ā§āϟāϟāĻŋ āĻŽā§‚āϞ JSX Return āĻ•āϰāĻŦ⧇ āύāĻž, āĻāĻ•āϟāĻž Promise āĻĨā§āϰ⧋ āĻ•āϰ⧇āĨ¤
  2. React āĻĻ⧇āϖ⧇, “āĻ“āĻš! Suspense āφāϛ⧇ āĻ•āĻžāϛ⧇āχ?” — āϝāĻĻāĻŋ āĻĨāĻžāϕ⧇, āϏ⧇āϟāĻž fallback UI (āϝ⧇āĻŽāύ Loading spinner) āĻĻ⧇āĻ–āĻžāϤ⧇ āĻļ⧁āϰ⧁ āĻ•āϰ⧇āĨ¤ āϝāϤāĻ•ā§āώāĻŖ āύāĻž Promise āϰ⧇āϜāϞāĻ­ āĻšā§ŸāĨ¤
  3. 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>

🌀 āĻāϟāĻž āϕ⧀āĻ­āĻžāĻŦ⧇ āĻ•āĻžāϜ āĻ•āϰ⧇?

  1. Biography āύāĻž āφāϏāĻž āĻĒāĻ°ā§āϝāĻ¨ā§āϤ → BigSpinner āĻĻ⧇āĻ–āĻžāĻŦ⧇
  2. Biography āϚāϞ⧇ āĻāϞ⧇ → Biography āĻĻ⧇āĻ–āĻžāĻŦ⧇
  3. Albums āĻāĻ–āύ⧋ āύāĻž āĻāϞ⧇ → AlbumsGlimmer āĻĻ⧇āĻ–āĻžāĻŦ⧇
  4. Albums āφāϏāϞ⧇ → āĻĒ⧁āϰāĻž UI ready

đŸ§ŧ āϏāĻžāϰāĻžāĻ‚āĻļ – āϕ⧀ āĻļāĻŋāĻ–āϞāĻžāĻŽ?

āĻļāĻŋāϖ⧇āĻ›āĻŋāĻ…āĻ°ā§āĻĨ
<Suspense fallback={...}>āϞ⧋āĻĄāĻŋāĻ‚ UI āĻĻ⧇āĻ–āĻžāϤ⧇ āϏāĻžāĻšāĻžāĻ¯ā§āϝ āĻ•āϰ⧇
use()āĻĄā§‡āϟāĻž āϞ⧋āĻĄ āĻšā§Ÿā§‡ āϗ⧇āϞ⧇ āϰāĻŋāϟāĻžāĻ°ā§āύ, āύāĻž āĻšāϞ⧇ suspend āĻ•āϰ⧇
Nested SuspenseUI āϧāĻžāĻĒ⧇ āϧāĻžāĻĒ⧇ āĻĻ⧇āĻ–āĻžāύ⧋ āϝāĻžā§Ÿ
ErrorBoundaryāĻāϰāϰ āϧāϰāϤ⧇ āϞāĻžāϗ⧇
startTransitionUI āĻŸā§āϰāĻžāύāϜāĻŋāĻļāύ āĻ¸ā§āĻŽā§āĻĨ āϰāĻžāϖ⧇

🎁 Bonus Tip

React Suspense āĻāĻ–āύ⧋ evolving, āϤāĻžāχ āϏāĻŦ āĻĄā§‡āϟāĻž āĻĢ⧇āϚāĻŋāĻ‚ āϞāĻžāχāĻŦā§āϰ⧇āϰāĻŋ (āϝ⧇āĻŽāύ Axios) āϏāϰāĻžāϏāϰāĻŋ āϏāĻžāĻĒā§‹āĻ°ā§āϟ āĻ•āϰ⧇ āύāĻžāĨ¤ āϤāĻŦ⧇ Next.js āĻŦāĻž Relay āĻāϰ āĻŽāϤ⧋ āĻĢā§āϰ⧇āĻŽāĻ“ā§ŸāĻžāĻ°ā§āϕ⧇ Suspense āϖ⧁āĻŦ āĻ­āĻžāϞ⧋ āĻ•āĻžāϜ āĻ•āϰ⧇āĨ¤



Š 2024 - 2026 React JS Bangla Tutorial.