Home » blog » Modern React State Management: What You Actually Need

Modern React State Management: What You Actually Need

ইন্টারনেটে React State Management নিয়ে হাজারটা আর্টিকেল, ভিডিও আর ওপিনিয়ন পাবেন।

কেউ বলবে Redux ছাড়া উপায় নেই, কেউ বলবে নতুন Zustand বা Jotai শিখুন, আবার কেউ বলবে কনটেক্সট এপিআই থাকতে লাইব্রেরির কী দরকার?

ডেভেলপারদের এই কনফিউশনের বাজারে আজ আমরা একদম সোজাসাপ্টা কথা বলব।

React State Management
React State Management

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

আসল সত্যটা কী? আপনার কি আদৌ গ্লোবাল স্টেট লাইব্রেরি লাগবে?

এক লাইনে উত্তর দিলে অধিকাংশ প্রজেক্টে আপনার কোনো ডেডিকেটেড গ্লোবাল স্টেট ম্যানেজমেন্ট লাইব্রেরির (যেমন Redux বা Zustand) প্রয়োজনই নেই।

পুরোনো দিনে (Redux-এর শুরুর দিকে) অ্যাপের যাবতীয় ডেটা সেটা এপিআই রেসপন্স হোক, ড্রপডাউন ওপেন-ক্লোজ স্টেট হোক বা ইউআরএল প্যারামিটার হোক সব জোর করে একটি সেন্ট্রাল গ্লোবাল স্টোরে ঢুকিয়ে দেওয়া হতো।

কিন্তু মডার্ন রিয়্যাক্ট ইকোসিস্টেমে স্টেটকে মূলত ৪টি ভাগে ভাগ করা যায়। এই ভাগগুলো গভীরভাবে বুঝলে লাইব্রেরির ওপর আপনার নির্ভরশীলতা এমনিতেই কেটে যাবে।

১. Remote React State Management (এপিআই বা ব্যাকএন্ডের ডেটা)

আপনার অ্যাপের প্রায় ৮০% স্টেট মূলত কী? ডেটাবেজ বা ব্যাকএন্ড এপিআই থেকে আসা ডেটা, যা আপনি সার্ভার থেকে ফেচ করে স্ক্রিনে দেখান।

একটি সাধারণ ফেচ রিকোয়েস্ট হ্যান্ডেল করতে গেলেও আমাদের অনেক কিছু নিয়ে ভাবতে হয়:

  • ডেটা লোড হওয়ার সময় লোডিং স্টেট হ্যান্ডেল করা।
  • সার্ভার ডাউন থাকলে বা কোনো সমস্যা হলে এরর স্টেট দেখানো।
  • ক্যাশিং মেকানিজম ম্যানেজ করা, যাতে একই এপিআই বারবার কল না হয়।
  • রিকোয়েস্ট ওয়াটারফল (Request Waterfalls) রোধ করা।
  • পেজিনেশন, ইনফিনিট স্ক্রোলিং এবং অপটিমিস্টিক আপডেট ম্যানেজ করা।

এই সমস্ত জটিল কাজের জন্য আপনার কোনো গ্লোবাল স্টেট ম্যানেজমেন্ট লাইব্রেরি লাগবে না। আপনার দরকার একটি রিয়্যাক্ট-ফার্স্ট ডেটা ম্যানেজমেন্ট ইঞ্জিন।

আমাদের রেকমেন্ডেশন: TanStack Query (React Query) অথবা SWR

এই লাইব্রেরিগুলো আপনার কোডবেস থেকে শত শত লাইনের বয়লারপ্লেট কোড কমিয়ে দেয়। যেমন TanStack Query-র একটি বাস্তব উদাহরণ লক্ষ্য করুন:

function UserProfile() {
  const { isPending, error, data } = useQuery({
    queryKey: ['userData'],
    queryFn: () => fetch('https://api.example.com/user').then(res => res.json()),
  });
 
  if (isPending) return 'Loading...';
  if (error) return 'Oops, something went wrong';
 
  return <div>Hello, {data.name}</div>;
}

এখানে সবচেয়ে বড় সুবিধা হলো, আপনি অ্যাপের যেকোনো দূরবর্তী কম্পোনেন্টে এই একই কোড লিখলে সে নতুন করে নেটওয়ার্ক রিকোয়েস্ট পাঠাবে না।

সে বুদ্ধিমান ইউনিক কুয়েরি কি (queryKey) দেখে বুঝতে পারবে যে ডেটা অলরেডি ক্যাশে আছে এবং সেখান থেকেই ইনস্ট্যান্ট ডেটা প্রোভাইড করবে। অর্থাৎ ব্যাকএন্ড ডেটা ম্যানেজমেন্টের জন্য এটিই আলটিমেট সলিউশন।

২. URL State (ইউআরএলের কুয়েরি প্যারামিটার)

ওয়েবসাইটের URL-ও কিন্তু এক ধরনের পাওয়ারফুল স্টেট।

যেমন একটি ই-কমার্স সাইটের ফিল্টার পেজের ইউআরএল খেয়াল করুন: /products?search=laptop&category=electronics. এখানে সার্চ টার্ম কিংবা ক্যাটাগরির ডেটাগুলো কিন্তু ইউআরএল-এই স্টোর করা আছে।

অনেকে এই ডেটাগুলোকে লোকাল স্টেটে নিয়ে আবার ইউআরএলের সাথে সিঙ্ক করার জন্য useEffect দিয়ে জটিল লজিক লেখেন।

এটি অ্যাপে রেস কন্ডিশন (Race Conditions), ইনফিনিট লুপ এবং ব্রাউজার হিস্ট্রি ব্লটের মতো মারাত্মক বাগ তৈরি করে।

আমাদের রেকমেন্ডেশন: nuqs লাইব্রেরি

যদি আপনি Next.js বা মডার্ন কোনো ফাইল-বেসড রাউটার ব্যবহার করেন, তবে nuqs লাইব্রেরিটি ব্যবহার করতে পারেন।

এটি ইউআরএলের কুয়েরি প্যারামসকে একদম রিয়্যাক্টের বিল্ট-ইন useState-এর মতো সহজ ও ডাইনামিক বানিয়ে দেয়।

export function FilterComponent() {
  const [search, setSearch] = useQueryState('search');
 
  return (
    <input 
      value={search || ''} 
      onChange={e => setSearch(e.target.value)} 
      placeholder="Search products..."
    />
  );
}

এখানে কোনো ম্যানুয়াল সিঙ্কিং বা ইউআরএল পুশ করার ঝামেলা নেই।

ইউজার ইনপুট বক্সে টাইপ করবে, ইউআরএল অটোমেটিক আপডেট হবে এবং পুরো অ্যাপ সেই ইউআরএল স্টেট অনুযায়ী রিয়্যাক্ট করবে। একই সাথে পেজটি রিফ্রেশ করলেও ফিল্টার ডেটা হারিয়ে যাবে না।

৩. Local State (কম্পোনেন্টের নিজস্ব স্টেট)

একটি নির্দিষ্ট মোডাল বা ড্রপডাউন ওপেন আছে কিনা, একটা ফর্মের ইনপুট ফিল্ডের ভ্যালু কী এগুলো হলো পিওর লোকাল স্টেট। এই ডেটাগুলো অ্যাপের অন্য কোনো দূরবর্তী কম্পোনেন্টের জানার কোনো দরকার নেই।

আমাদের রেকমেন্ডেশন: রিয়্যাক্টের বিল্ট-ইন useState এবং useReducer

এর জন্য কোনো থার্ড-পার্টি লাইব্রেরি ছোঁয়ারও প্রয়োজন নেই।

স্টেটকে যতটা সম্ভব ক্লোজড বা কম্পোনেন্টের ভেতরে (State Collocation) রাখাটাই ক্লিন কোডের প্রধান শর্ত।

লজিক যদি বেশি জটিল বা মাল্টিপল স্টেটের ওপর নির্ভরশীল হয়, তবে useReducer ব্যবহার করে লজিক আলাদা করে ফেলা যায়।

৪. Shared State (যখন ডেটা মাল্টিপল কম্পোনেন্টে শেয়ার করতে হয়)

আসল চ্যালেঞ্জটা শুরু হয় তখনই, যখন অ্যাপের একদম আলাদা দুটি বা তিনটি ডিপলি নেস্টেড কম্পোনেন্টের মধ্যে একই স্টেট শেয়ার করতে হয়।

যেমন: সাইডবার ওপেন/ক্লোজ স্টেট, থিমিং (Dark/Light mode), অথবা কারেন্টলি লগড-ইন ইউজারের ইনফরমেশন।

এখানে আমাদের সামনে দুটি পথ থাকে:

কনটেক্সট এপিআই (Context API) এবং এর সীমাবদ্ধতা

স্টেট শেয়ার করার জন্য আমরা প্যারেন্ট কম্পোনেন্ট থেকে চাইল্ড কম্পোনেন্টে প্রপস পাঠাতে পারি।

কিন্তু লেভেল যদি ৩-৪ টার বেশি হয়ে যায়, তখন কোড রিডাবিলিটি নষ্ট হয়, যাকে আমরা প্রপ ড্রিলিং (Prop Drilling) বলি।

এই সমস্যার সমাধানে রিয়্যাক্ট আমাদের কনটেক্সট এপিআই দেয়।

তবে কনটেক্সটের একটি বড় পারফরম্যান্স ড্রব্যাক আছে। কনটেক্সটের ভেতরের কোনো একটি ভ্যালু চেঞ্জ হলে, ওই কনটেক্সট কনজিউম করা প্রত্যেকটি চাইল্ড কম্পোনেন্ট ফোর্সড রি-রেন্ডার হয় এমনকি তারা যদি সেই নির্দিষ্ট চেঞ্জ হওয়া ভ্যালুটা ব্যবহার নাও করে।

তাছাড়া অ্যাপ বড় হওয়ার সাথে সাথে ডেভেলপাররা পুরো অ্যাপকে ডজন খানেক কনটেক্সট প্রোভাইডার দিয়ে মুড়িয়ে ফেলেন, যাকে বলা হয় প্রোভাইডার হেল (Providers Hell)।

এটি কোড মেইনটেইন করা অসম্ভব করে তোলে। ঠিক এই সিনারিওতেই আমাদের একটি এক্সটার্নাল স্টেট ম্যানেজমেন্ট লাইব্রেরি দরকার হয়।

মডার্ন React State Management লাইব্রেরি: কোনটি আপনার জন্য পারফেক্ট?

যদি আপনার প্রজেক্টের আর্কিটেকচারে এক্সটার্নাল লাইব্রেরি মাস্ট হয়ে দাঁড়ায়, তবে বাজারের পপুলার লাইব্রেরিগুলোর ভেতরের মেকানিজম আপনার জানা উচিত।

Zustand: সিম্পলিসিটি এবং পারফরম্যান্সের সেরা কম্বিনেশন

মডার্ন রিয়্যাক্ট এবং Next.js (SSR/RSC) ইকোসিস্টেমে এই মুহূর্তে সবচেয়ে এফিশিয়েন্ট লাইব্রেরি হলো Zustand।

এর মেকানিজম অত্যন্ত ক্লিন কোনো প্রোভাইডার হেলের ঝামেলা নেই, পুরো অ্যাপ র্যাপ করতে হয় না। স্রেফ একটি ইন্ডিপেন্ডেন্ট স্টোর ক্রিয়েট করবেন আর হুকের মতো যেকোনো কম্পোনেন্টে কল করবেন।

Zustand-এর সবচেয়ে পাওয়ারফুল দিক হলো এর সিলেক্টর-বেসড সাবস্ক্রিপশন।

স্টোরের কোনো একটি নির্দিষ্ট স্টেট চেঞ্জ হলে শুধু সেই কম্পোনেন্টই রি-রেন্ডার হবে যা ওই স্টেটটি সিলেক্ট করেছে। আন্ডার দ্য হুড এটি রিয়্যাক্টের useSyncExternalStore ব্যবহার করে পারফরম্যান্স অপ্টিমাইজড রাখে।

import { create } from 'zustand'

const useSidebarStore = create((set) => ({
  isOpen: false,
  toggleSidebar: () => set((state) => ({ isOpen: !state.isOpen })),
}))

// কম্পোনেন্টে ব্যবহার:
function SidebarButton() {
  const toggleSidebar = useSidebarStore((state) => state.toggleSidebar)
  return <button onClick={toggleSidebar}>Toggle Sidebar</button>
}

Redux Toolkit (RTK): এন্টারপ্রাইজ প্রজেক্টের স্ট্যান্ডার্ড

রেডক্স অনেক পুরোনো এবং ট্রাস্টেড হলেও এর অতিরিক্ত বয়লারপ্লেট কোডের কারণে অনেকে এটি এড়িয়ে চলেন।

তবে Redux Toolkit আসার পর এই জটিলতা অনেক কমেছে।

যদি আপনি এমন কোনো বড় এন্টারপ্রাইজ টিমে কাজ করেন যেখানে কঠোর নিয়ম, স্ট্রাকচার্ড গাইডলাইন এবং অ্যাডভান্সড ডিবাগিং (Redux DevTools-এর টাইম ট্রাভেল ডিবাগিং) সবচেয়ে বেশি গুরুত্বপূর্ণ, তবে Redux Toolkit এখনও একটি শক্তিশালী চয়েস।

এটি কোড রাইটিংয়ে এক ধরনের কনসিস্টেন্সি বজায় রাখতে বাধ্য করে, যা বড় অর্গানাইজেশনে টিম কোলাবোরেশনের জন্য বেশ সুবিধাজনক।

Jotai এবং XState: স্পেসিফিক ইউজার কেস

Jotai মূলত অ্যাটম-বেসড (Atom-based) স্টেট ম্যানেজমেন্ট।

যদি আপনার অ্যাপের স্টেটগুলো খুব ক্ষুদ্র বা ফাইন-গ্রেইন্ড (Fine-grained) হয় এবং একটি স্টেটের পরিবর্তনের ওপর ভিত্তি করে আরেকটি স্টেট ডাইনামিকালি ক্যালকুলেট করতে হয়, তবে Jotai ভালো অপশন।

অন্যদিকে XState হলো স্টেট মেশিন (State Machine) আর্কিটেকচার। এটি সাধারণ ক্রুড (CRUD) অ্যাপের জন্য অত্যন্ত জটিল এবং ওভারকিল।

তবে আপনি যদি ফিগমা (Figma) বা কোনো জটিল ড্রয়িং টুলস, মাল্টি-স্টেপ গেম বা হাইলি কন্ডিশনাল ওয়ার্কফ্লো তৈরি করেন, যেখানে স্টেটের লজিক ট্র্যাক করা অসম্ভব হয়ে যায়, একমাত্র তখনই XState ব্যবহার করা উচিত।

Summary:

Modern React state management has shifted away from forcing all application data into a single, massive global store like Redux. To achieve peak React performance optimization, developers should break state down into four distinct concerns: remote, URL, local, and shared. Utilizing targeted engines like TanStack Query for API data, nuqs for URL query parameters, and native hooks for local UI elements eliminates up to 90% of custom boilerplate code.

All Tech Update

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

Scroll to Top