چه زمانی واقعاً به یک ابزار State Management نیاز داریم

در دو درس قبل، سطوح مختلف State و تفاوت Client State با Server State را دیدیم. اما این سؤال باقی می‌ماند: چه زمانی useState و Context ساده دیگر کافی نیستند و باید به سراغ یک کتابخانه مدیریت State برویم؟ این درس، نشانه‌های واقعی این نیاز را بررسی می‌کند.

یک باور اشتباه رایج

بسیاری از تیم‌ها، یک کتابخانه مدیریت State را از همان روز اول پروژه اضافه می‌کنند، فقط چون «برنامه‌های بزرگ به آن نیاز دارند». اما همان‌طور که در فصل‌های قبل دیدیم، React.memo، useMemo و useReducer، همگی ابزارهایی هستند که هزینه و پیچیدگی خودشان را دارند؛ یک کتابخانه مدیریت State هم از این قاعده مستثنا نیست.

نشانه اول: Prop Drilling عمیق و واقعی

در فصل هشتم دیدیم Context، راه‌حل React برای Prop Drilling است. اگر Context به‌تنهایی کافی است (یعنی چند مقدار مشخص، در چند Provider جدا)، نیازی به ابزار بیرونی نیست. نشانه واقعی نیاز، وقتی است که ده‌ها مقدار مختلف، با رابطه‌های پیچیده بین‌شان، باید مدیریت شوند و Contextهای جدا، خودشان به مشکل تبدیل شده‌اند.

نشانه دوم: تکرار همان منطق State در جاهای مختلف

اگر متوجه شدید همان الگوی Reducer، یا همان منطق به‌روزرسانی، در چند بخش مختلف برنامه (که هیچ رابطه Context مشترکی هم ندارند) تکرار شده، این نشانه‌ای است که شاید یک لایه مدیریت State سازمان‌یافته‌تر لازم است.

نشانه سوم: نیاز به ابزارهای توسعه‌دهنده پیشرفته

بعضی کتابخانه‌های مدیریت State، ابزارهایی مثل سفر در زمان (Time Travel Debugging) یا ثبت دقیق هر تغییر State ارائه می‌دهند. اگر پیچیدگی تعاملات State در برنامه به‌قدری زیاد شده که ردیابی دستی علت هر تغییر سخت شده، این ابزارها واقعاً ارزشمند می‌شوند.

چیزی که نشانه نیست: فقط «بزرگ بودن» برنامه

اندازه کد به‌تنهایی معیار خوبی نیست. یک برنامه بزرگ با بخش‌های نسبتاً مستقل از هم (که هرکدام State محلی خودشان را دارند)، ممکن است هیچ‌وقت به یک Store مرکزی نیاز پیدا نکند؛ در حالی که یک برنامه کوچک‌تر، اما با تعامل پیچیده بین بخش‌های مختلف، ممکن است زودتر به این نیاز برسد.

یک راه عملی: صبر کردن تا درد واقعی حس شود

رویکردی که در عمل بیشتر جواب می‌دهد، شروع با ابزارهای ساده React (useState، useReducer، Context) و اضافه کردن یک کتابخانه بیرونی فقط وقتی است که یکی از نشانه‌های بالا، به‌طور ملموس، روی سرعت توسعه یا تعداد باگ‌ها اثر گذاشته باشد؛ نه به‌عنوان یک تصمیم پیشگیرانه از ابتدای کار.

مثال قابل اجرا

در این مثال، یک برنامه کوچک با دو Context مستقل، بدون نیاز به هیچ ابزار بیرونی، به‌خوبی مدیریت شده است؛ نمونه‌ای از این‌که «بزرگ‌تر شدن کد» الزاماً یعنی نیاز به ابزار جدید نیست.

مدیریت کافی با Context ساده، بدون ابزار بیرونی
import { createContext, useContext, useState } from "react";

const CartContext = createContext(null);

function CartProvider({ children }) {
  const [items, setItems] = useState([]);
  function addItem(name) {
    setItems((prev) => [...prev, name]);
  }
  return (
    <CartContext.Provider value={{ items, addItem }}>
      {children}
    </CartContext.Provider>
  );
}

function AddButton() {
  const { addItem } = useContext(CartContext);
  return <button onClick={() => addItem("محصول")}>افزودن</button>;
}

function CartCount() {
  const { items } = useContext(CartContext);
  return <p>تعداد: {items.length}</p>;
}

function App() {
  return (
    <CartProvider>
      <AddButton />
      <CartCount />
    </CartProvider>
  );
}
برای دیدن پیش‌نمایش کامپوننت، روی Run بزنید.

جمع‌بندی

نیاز واقعی به یک ابزار State Management، از نشانه‌های مشخصی می‌آید: Prop Drilling عمیق که Context هم آن را حل نمی‌کند، تکرار گسترده همان منطق در جاهای مختلف، یا نیاز واقعی به ابزارهای پیشرفته دیباگ؛ نه صرفاً بزرگ بودن برنامه. رویکرد عملی، شروع ساده و اضافه کردن ابزار بیرونی فقط پس از حس کردن یک مشکل واقعی است. در درس بعدی، به Trade-off های دقیق‌تر این تصمیم می‌پردازیم.