Home » blog » Next JS Data Fetching in App Router

Next JS Data Fetching in App Router

ওয়েব ডেভেলপমেন্টের দুনিয়ায় Next.js এখন একটি স্ট্যান্ডার্ড ফ্রেমওয়ার্ক।

বিশেষ করে Next.js ১৩-তে যখন “App Router” এবং React Server Components (RSC) ইন্ট্রোডিউস করা হলো, তখন থেকে ওয়েব অ্যাপ্লিকেশনের আর্কিটেকচার পুরোপুরি বদলে গেছে।

যেকোনো ডায়নামিক ওয়েবসাইটের (যেমন: ই-কমার্স, ড্যাশবোর্ড বা ব্লগ) কোর ইঞ্জিন হলো এর ডেটা। ডেটাবেস বা API থেকে ইউজারের স্ক্রিন পর্যন্ত এই ডেটা অত্যন্ত দ্রুত এবং সিকিউরলি পৌঁছে দেওয়ার পুরো প্রসেসটাকেই আমরা বলি ডেটা ফেচিং।

আপনি যদি একজন প্রফেশনাল ওয়েব ডেভেলপার হন এবং স্কেলেবল ওয়েব অ্যাপ বানাতে চান, তবে next js data fetching-এর কোর কনসেপ্টগুলো আপনার জেনে থাকা চাই।

Introduction: Why Next JS Data Fetching is a Game Changer

আগে React-এর ট্র্যাডিশনাল অ্যাপ্লিকেশনগুলোতে ডেটা ফেচিং মেইনলি ক্লায়েন্ট সাইডে (Client-side) হতো।

ইউজার সাইটে ঢোকার পর প্রথমে একটা ব্ল্যাংক স্ক্রিন বা স্পিনার দেখতো, ব্যাকগ্রাউন্ডে পুরো জাভাস্ক্রিপ্ট বান্ডেল ডাউনলোড হতো, তারপর useEffect কল হয়ে API থেকে ডেটা আসতো। এই প্রসেসটি ইউজার এক্সপেরিয়েন্স (UX) এবং SEO উভয় ক্ষেত্রেই বেশ ক্ষতিকর ছিল।

Next.js-এর App Router এই সমস্যার দারুণ একটা সলিউশন নিয়ে এসেছে। এখানে ডিফল্টভাবে সব কম্পোনেন্টই Server Component। এর মানে হলো, আপনার next js data fetching প্রসেসটি ইউজারের ব্রাউজারের বদলে সরাসরি সার্ভারে এক্সিকিউট হবে।

Server-side Data Fetching-এর প্রধান সুবিধাগুলো:

  • Zero Client-Side JavaScript: ডেটা ফেচিংয়ের জন্য ক্লায়েন্টে এক্সট্রা কোড যায় না, বান্ডেল সাইজ ছোট থাকে।
  • Top-Notch Security: ডেটাবেস ক্রেডেনশিয়াল এবং API Keys সার্ভারেই সেফ থাকে।
  • Faster Rendering: সার্ভার থেকে ডেটাসহ HTML পেজ আসে, Initial Page Load অনেক ফাস্ট হয়।
  • SEO Boost: সার্চ ইঞ্জিন ক্রলাররা সম্পূর্ণ ডেটাসহ পেজ সহজেই ইনডেক্স করতে পারে।

Fetching Data in Server Components

Next.js App Router-এ ডেটা ফেচ করার সবচেয়ে রেকমেন্ডেড উপায় হলো Server Components ব্যবহার করা।

যেহেতু এগুলো সার্ভারেই রেন্ডার হয়, তাই আপনি যেকোনো Asynchronous I/O অপারেশন (যেমন: নেটিভ fetch API বা সরাসরি ডেটাবেস কুয়েরি) খুব ইজিলি করতে পারেন।

1. Using the Native Fetch API

Next.js নেটিভ ওয়েব fetch API-কে ওভাররাইড করে এটিকে আরও পাওয়ারফুল করেছে। সার্ভার কম্পোনেন্টে fetch ব্যবহার করতে হলে, আপনার কম্পোনেন্টটিকে জাস্ট একটি async ফাংশন বানাতে হবে এবং fetch কলটিকে await করতে হবে।

TypeScript

// app/blog/page.tsx

export default async function BlogPage() {
  // External API থেকে ডেটা ফেচ করা হচ্ছে
  const response = await fetch('https://api.vercel.app/blog');
  const posts = await response.json();

  return (
    <div className="container mx-auto p-4">
      <h1 className="text-3xl font-bold mb-6">Latest Blog Posts</h1>
      <ul className="grid grid-cols-1 md:grid-cols-3 gap-4">
        {posts.map((post: any) => (
          <li key={post.id} className="p-4 border rounded-lg shadow-sm">
            <h2 className="text-xl font-semibold">{post.title}</h2>
            <p className="text-gray-600 mt-2">{post.body}</p>
          </li>
        ))}
      </ul>
    </div>
  );
}

Important Behaviors:

  • Request Memoization: একই fetch রিকোয়েস্ট একাধিকবার কল হলে Next.js তা মেমোইজ করে, ফলে নেটওয়ার্ক রিকোয়েস্ট একবারই যায়।
  • Default Caching: ডিফল্টভাবে fetch রিকোয়েস্টগুলো ক্যাশ করা থাকে না।

2. Fetching Data with an ORM or Database

অনেক সময় থার্ড-পার্টি API থাকে না, সরাসরি ডেটাবেস থেকে ডেটা কোয়েরি করতে হয়। Server Components-এ আপনি সরাসরি ORM (যেমন Prisma, Drizzle) ব্যবহার করতে পারবেন, এবং Database Credentials সম্পূর্ণ সেফ থাকে।

TypeScript

// app/users/page.tsx
import { db, users } from '@/lib/db'; 

export default async function UsersPage() {
  const allUsers = await db.select().from(users);

  return (
    <main>
      <h1>Registered Users</h1>
      <ul>
        {allUsers.map((user) => (
          <li key={user.id}>{user.name} - {user.email}</li>
        ))}
      </ul>
    </main>
  );
}

Pro Tip: সরাসরি ডেটাবেস কল করার সময় ডেটা রিকোয়েস্টগুলো অথেনটিকেটেড (Authenticated) এবং অথোরাইজড (Authorized) কি না নিশ্চিত করুন।

Streaming and Progressive Rendering

সার্ভার কম্পোনেন্টে ডেটা ফেচ করার একটা সমস্যা হলো ডেটাবেস বা API রেসপন্স দিতে দেরি করলে পেজ রেন্ডারিং ব্লক হয়ে থাকে। এর সমাধান হলো Streaming।

স্ট্রিমিংয়ে পুরো পেজ একসাথে রেন্ডার হওয়ার জন্য অপেক্ষা না করে, পেজটিকে ছোট ছোট চাঙ্কে (Chunks) ভাগ করে প্রগ্রেসিভলি ক্লায়েন্টের কাছে পাঠানো হয়।

Streaming and Progressive Rendering
Streaming and Progressive Rendering

Using loading.js for Route Segment Streaming

পুরো পেজের জন্য গ্লোবাল লোডিং স্টেট তৈরি করতে রাউট ফোল্ডারে loading.tsx ফাইল অ্যাড করুন।

TypeScript

// app/dashboard/loading.tsx

export default function Loading() {
  return (
    <div className="flex justify-center items-center h-screen">
      <div className="animate-spin rounded-full h-12 w-12 border-t-2 border-blue-500"></div>
      <span className="ml-3 text-lg font-medium">Fetching Dashboard Data...</span>
    </div>
  );
}

ডেটা ফেচিং শেষ না হওয়া পর্যন্ত ইউজার এই স্পিনারটি দেখবে।

Granular Streaming with React <Suspense>

পেজের নির্দিষ্ট অংশে লোডিং স্টেট দেখাতে কাস্টম <Suspense> বাউন্ডারি ব্যবহার করুন।

TypeScript

// app/dashboard/page.tsx

import { Suspense } from 'react';
import RevenueChart from '@/components/RevenueChart';
import SkeletonChart from '@/components/skeletons/SkeletonChart';

export default function DashboardPage() {
  return (
    <div className="dashboard-layout">
      <header>
        <h1>Welcome to your Dashboard</h1>
      </header>
      
      <div className="grid">
        <Suspense fallback={<SkeletonChart />}>
          <RevenueChart />
        </Suspense>
      </div>
    </div>
  );
}

Fetching Data in Client Components

Next.js-এ সবসময় Server Component-এ ডেটা ফেচ করা রেকমেন্ডেড, তবে ইউজার ইন্টারঅ্যাকশনের (যেমন onClick) কারণে ক্লায়েন্ট সাইডেও ডেটা ফেচিং লাগতে পারে।

Streaming Data with the React use API

সার্ভার কম্পোনেন্টে প্রমিজ তৈরি করে ক্লায়েন্ট কম্পোনেন্টে use() হুক দিয়ে আনর‍্যাপ করতে পারেন।

Step 1: Server Component (Promise তৈরি করা)

TypeScript

import Posts from '@/components/Posts';
import { Suspense } from 'react';

function getPostsPromise() {
  return fetch('https://api.vercel.app/blog').then(res => res.json());
}

export default function Page() {
  const postsPromise = getPostsPromise();

  return (
    <Suspense fallback={<div>Loading posts...</div>}>
      <Posts postsPromise={postsPromise} />
    </Suspense>
  );
}

Step 2: Client Component (Promise Unwrap করা)

TypeScript

'use client';
import { use } from 'react';

export default function Posts({ postsPromise }: { postsPromise: Promise<any[]> }) {
  const posts = use(postsPromise);

  return (
    <ul>
      {posts.map((post) => (
        <li key={post.id}>{post.title}</li>
      ))}
    </ul>
  );
}

Client-Side Fetching with SWR or TanStack Query

রিয়েল-টাইম ডেটা রিফ্রেশ বা মিউটেশনের জন্য ক্লাসিক useEffect-এর বদলে SWR বা TanStack Query ব্যবহার করা বেস্ট চয়েস।

TypeScript

'use client';
import useSWR from 'swr';

const fetcher = (url: string) => fetch(url).then((res) => res.json());

export default function UserProfile() {
  const { data, error, isLoading } = useSWR('/api/user/profile', fetcher);

  if (error) return <div className="error">Failed to load profile!</div>;
  if (isLoading) return <div className="spinner">Loading your data...</div>;

  return (
    <div className="profile-card">
      <h2>Welcome back, {data.name}!</h2>
    </div>
  );
}

Advanced Patterns: Sequential vs. Parallel Data Fetching

FeatureSequential FetchingParallel Fetching
Conceptএকটি রিকোয়েস্ট শেষ হলে পরেরটি শুরু হয়।একাধিক রিকোয়েস্ট একই সাথে ফায়ার করা হয়।
Use Caseযখন দ্বিতীয় রিকোয়েস্ট প্রথমটির ডেটার ওপর নির্ভর করে।যখন রিকোয়েস্টগুলো স্বাধীন থাকে।
Performanceধীরগতির, Waterfall ইফেক্ট তৈরি করে।অত্যন্ত দ্রুত, রেন্ডারিং স্পিড বাড়ায়।
Code Structureawait fetch1(), তারপর await fetch2()Promise.all([fetch1(), fetch2()])

Parallel Fetching Example:

TypeScript

import { fetchUserMetrics, fetchRecentOrders } from '@/lib/api';

export default async function Dashboard({ params }: { params: { id: string } }) {
  const metricsData = fetchUserMetrics(params.id);
  const ordersData = fetchRecentOrders(params.id);

  const [metrics, orders] = await Promise.all([metricsData, ordersData]);

  return (
    <main>
      <MetricsCard data={metrics} />
      <OrdersTable data={orders} />
    </main>
  );
}

Caching, Revalidating, and SEO

ডেটা কতক্ষণ ক্যাশ থাকবে তা কন্ট্রোল করা খুবই জরুরি:

  • No Store: প্রতি রিকোয়েস্টে নতুন ডেটা আনতে ক্যাশ ডিসেবল করা।
  • Time-based Revalidation: নির্দিষ্ট সময় পর পর ডেটা আপডেট করা।
  • On-Demand Revalidation: revalidatePath বা revalidateTag দিয়ে ডাটা আপডেট হওয়ামাত্রই ক্যাশ ক্লিয়ার করা।

SEO Benefits:

  • Instant Indexing: সার্ভারে ডেটা প্রসেস হয়ে HTML তৈরি হওয়ায় ক্রলার সাথে সাথে সব কন্টেন্ট পেয়ে যায়।
  • Better Web Vitals: LCP (Largest Contentful Paint) স্কোর দুর্দান্ত আসে।
  • Dynamic Meta Tags: সোশ্যাল প্রিভিউর জন্য ডায়নামিক OG ট্যাগ তৈরি করা যায়।

Best Practices for Developers

  1. Server Components First: ইন্টারঅ্যাকটিভিটি না লাগলে সার্ভারেই ডেটা ফেচ করুন।
  2. Keep Secrets Secure: API Keys বা ডেটাবেস কানেকশন ক্লায়েন্ট সাইডে লিক করবেন না।
  3. Use Suspense Boundaries: ভারী ডেটাবেস কোয়েরিগুলো <Suspense> দিয়ে আইসোলেট করুন।
  4. Error Handling: প্রতিটি রাউট ফোল্ডারে error.tsx ফাইল রাখুন।
  5. Avoid Props Drilling: যে কম্পোনেন্টে ডেটা লাগবে, সেখানেই আবার fetch কল করুন।

Final Thoughts on Next JS App Router

Next.js App Router এবং এর ডেটা ফেচিং মডেল ওয়েব ডেভেলপমেন্ট ইকোসিস্টেমে আক্ষরিক অর্থেই একটি বিপ্লব নিয়ে এসেছে।

বিশেষ করে ডেভেলপার এক্সপেরিয়েন্স (DX) এবং ইউজার এক্সপেরিয়েন্স (UX)-এর যে অদ্ভুত এক ব্লেন্ডিং এখানে করা হয়েছে, তা সত্যিই প্রশংসনীয়।

next js data fetching-এর এই জার্নিতে সার্ভার কম্পোনেন্টের সিকিউরিটি, প্যারালাল ফেচিংয়ের স্পিড এবং স্ট্রিমিংয়ের ম্যাজিক আপনার ওয়েব অ্যাপ্লিকেশনকে নেক্সট লেভেলে নিয়ে যাবে।

আপনি যদি AI-পাওয়ার্ড অ্যাপ্লিকেশন, ড্যাশবোর্ড বা বড় স্কেলের প্রজেক্ট নিয়ে কাজ করেন, তবে এই কনসেপ্টগুলো আপনার প্রতিদিনের কোডিং লাইফকে অনেক বেশি স্মুথ আর প্রোডাক্টিভ করে তুলবে।

বেস্ট অফ লাক আপনার নেক্সট প্রোজেক্টের জন্য! হ্যাপি কোডিং!

All Tech Update

Technology এর সকল আপডেট সবার আগে বিস্তারিত পড়ুন –

Scroll to Top