পর্ব ৪-এ বলেছিলাম, Server Component-এ isLoading state ম্যানুয়ালি লেখার দরকার নেই। এই পর্বে দেখব কীভাবে — Next.js-এর দুটো বিশেষ ফাইল, loading.js আর error.js, আর React-এর Suspense দিয়ে।
loading.js — স্বয়ংক্রিয় লোডিং UI
একটা রুট ফোল্ডারে page.js-এর পাশে loading.js রাখলেই, সেই পেজের fetch শেষ না হওয়া পর্যন্ত Next.js স্বয়ংক্রিয়ভাবে এই ফাইলের কনটেন্ট দেখায়।
app/
└── books/
├── loading.js # /books লোড হওয়ার সময় দেখানো হবে
└── page.js # আসল পেজ, fetch করছে
// app/books/loading.js
export default function Loading() {
return <p>বই লোড হচ্ছে...</p>;
}
// app/books/page.js
async function getBooks() {
const res = await fetch("https://.../books.json");
return res.json();
}
export default async function BooksPage() {
const books = await getBooks(); // এই সময়টুকু loading.js দেখানো হবে
return <div>{/* ... */}</div>;
}
কোনো isLoading state, কোনো conditional rendering — Next.js নিজে থেকেই বুঝে নেয় কখন page.js এখনো ডেটার জন্য অপেক্ষা করছে, আর তখন loading.js দেখায়।
error.js — স্বয়ংক্রিয় এরর UI
একইভাবে, error.js রাখলে সেই রুটে কোনো এরর হলে (fetch ব্যর্থ হলে, কোনো এক্সেপশন থ্রো হলে) Next.js স্বয়ংক্রিয়ভাবে এই ফাইলের কনটেন্ট দেখায়, পুরো সাইট ক্র্যাশ না করিয়ে।
// app/books/error.js
"use client"; // error.js সবসময় Client Component হতে হয়
export default function Error({ error, reset }) {
return (
<div>
<p>কিছু একটা সমস্যা হয়েছে: {error.message}</p>
<button onClick={() => reset()}>আবার চেষ্টা করো</button>
</div>
);
}
গুরুত্বপূর্ণ: error.js-এ অবশ্যই "use client" লাগবে (পর্ব ৩-এর নিয়ম), কারণ এতে reset ফাংশনের মতো একটা ইন্টারঅ্যাক্টিভ বাটন থাকে, যা ক্লিক করলে সেই অংশটা আবার রেন্ডার করার চেষ্টা করে।
// app/books/page.js — এরর হলে error.js দেখাবে
async function getBooks() {
const res = await fetch("https://.../books.json");
if (!res.ok) {
throw new Error("বই লোড করা যায়নি"); // এটাই error.js-এ ধরা পড়বে
}
return res.json();
}
Nested Loading/Error — ফোল্ডার অনুযায়ী প্রযোজ্য
পর্ব ২-এর নেস্টেড লেআউটের মতোই, loading.js/error.js-ও নির্দিষ্ট ফোল্ডারে রাখলে শুধু সেই সেকশনেই প্রযোজ্য হয়।
app/
├── loading.js # পুরো সাইটের ডিফল্ট লোডিং
├── books/
│ ├── loading.js # শুধু /books-এর জন্য আলাদা লোডিং UI
│ └── page.js
└── dashboard/
├── error.js # শুধু /dashboard-এর জন্য আলাদা এরর UI
└── page.js
Suspense — পেজের একটা অংশের জন্য লোডিং
loading.js পুরো পেজের জন্য কাজ করে। কিন্তু একটা পেজে যদি কিছু কনটেন্ট দ্রুত রেডি হয় আর কিছু ধীরে, পুরো পেজ অপেক্ষা করানোর বদলে React-এর Suspense দিয়ে নির্দিষ্ট অংশ আলাদাভাবে লোড দেখানো যায়।
import { Suspense } from "react";
async function BookList() {
const res = await fetch("https://.../books.json", { cache: "no-store" });
const books = await res.json();
return (
<ul>
{Object.values(books || {}).map((b, i) => <li key={i}>{b.title}</li>)}
</ul>
);
}
export default function BooksPage() {
return (
<div>
<h1>বইয়ের তালিকা</h1> {/* সাথে সাথেই দেখা যাবে */}
<Suspense fallback={<p>বই লোড হচ্ছে...</p>}>
<BookList /> {/* এইটুকু আলাদাভাবে লোড হবে */}
</Suspense>
</div>
);
}
এখানে <h1> সাথে সাথে দেখা যায়, শুধু BookList-এর ডেটা রেডি না হওয়া পর্যন্ত সেই অংশে fallback দেখানো হয় — এটা পুরো পেজ ব্লক করার চেয়ে অনেক ভালো ইউজার এক্সপিরিয়েন্স দেয়।
loading.js vs Suspense — কখন কোনটা
| পরিস্থিতি | ব্যবহার করুন |
|---|---|
| পুরো পেজই একটা fetch-এর ওপর নির্ভরশীল | loading.js |
| পেজের কিছু অংশ দ্রুত, কিছু ধীর | Suspense নির্দিষ্ট অংশে |
| একই পেজে একাধিক স্বাধীন ডেটা সোর্স | একাধিক Suspense, প্রতিটা আলাদা |
ইন্টারেক্টিভ — Suspense কীভাবে কাজ করে
নিচে দেখো একটা পেজে দ্রুত আর ধীর দুটো কনটেন্ট থাকলে Suspense কীভাবে সেগুলো আলাদাভাবে দেখায়।
ভালো অভ্যাস
- প্রতিটা মূল রুটে একটা loading.js রাখুন — না থাকলে ইউজার সাদা স্ক্রিন দেখবে, খারাপ অভিজ্ঞতা
- error.js-এ সবসময় reset বাটন দিন — ইউজারকে পুরো পেজ রিফ্রেশ না করেই আবার চেষ্টা করার সুযোগ দিন
- ধীর আর দ্রুত ডেটা একসাথে থাকলে Suspense দিয়ে আলাদা করুন — একটা ধীর fetch-এর জন্য পুরো পেজ আটকে রাখাটা এড়ানো যায়
নিজে চেষ্টা করো
Exercise:
- নিজের একটা পেজে
loading.jsযোগ করো, একটা ধীর API (বাsetTimeout-স্টাইল দেরি) দিয়ে টেস্ট করো। - একটা
error.jsবানাও, ইচ্ছাকৃতভাবে একটা এরর থ্রো করে টেস্ট করো,resetবাটন কাজ করছে কিনা যাচাই করো। - একটা পেজে দুটো আলাদা কম্পোনেন্ট রাখো — একটা দ্রুত, একটা ধীর ডেটা আনে —
Suspenseদিয়ে আলাদাভাবে র্যাপ করো।
পরের পর্বে যা থাকছে
পরের পর্বে আমরা শিখব API Routes — Next.js প্রজেক্টের ভেতরেই নিজের ব্যাকএন্ড এন্ডপয়েন্ট কীভাবে বানাতে হয়, ঠিক Cloudflare এর হাতেখড়ি পর্ব ৪-৫-এর Workers-এর মতোই, কিন্তু একই প্রজেক্টে।