Derived State: چه زمانی نباید یک مقدار جدید State تعریف کرد

یکی از اشتباهات رایج در نوشتن برنامه‌های React، تعریف State برای مقادیری است که در واقع می‌توان آن‌ها را مستقیماً از روی State یا Props موجود محاسبه کرد. به این نوع مقادیر، Derived State یا «حالت مشتق‌شده» گفته می‌شود، و شناخت آن یکی از مهم‌ترین مهارت‌ها در طراحی درست State است.

مشکل: State اضافی برای مقداری قابل‌محاسبه

فرض کنید لیستی از آیتم‌های سبد خرید داریم و می‌خواهیم تعداد کل آیتم‌ها را هم نمایش دهیم. یک رویکرد اشتباه، اما رایج در بین تازه‌کارها، این است:

function Cart({ items }) {
  const [totalCount, setTotalCount] = useState(0);

  useEffect(() => {
    setTotalCount(items.length);
  }, [items]);

  return <p>تعداد کل: {totalCount}</p>;
}

در این کد، totalCount یک State جداگانه است که با یک Effect، هر بار که items تغییر می‌کند، به‌روزرسانی می‌شود. این روش کار می‌کند، اما مشکلاتی دارد: یک رندر اضافه ایجاد می‌کند (چون ابتدا با مقدار قدیمی رندر می‌شود، سپس Effect اجرا و State جدید تنظیم و رندر دوباره انجام می‌شود)، و امکان دارد این دو مقدار به‌مرور از هم جدا بمانند و ناهماهنگ شوند.

راه‌حل: محاسبه مستقیم به‌جای State جداگانه

چون totalCount را می‌توان همیشه مستقیماً از روی items محاسبه کرد، اصلاً نیازی به State جداگانه یا Effect نیست:

function Cart({ items }) {
  const totalCount = items.length;

  return <p>تعداد کل: {totalCount}</p>;
}

در این نسخه، totalCount در هر رندر، مستقیماً و بدون تأخیر، از روی مقدار فعلی items محاسبه می‌شود. هیچ‌وقت این دو مقدار از هم عقب نمی‌مانند، چون اساساً دو مقدار جداگانه نیستند.

قانون کلی: اگر می‌توان محاسبه کرد، State نسازید

یک قاعده مفید این است: قبل از تعریف یک State جدید، از خودتان بپرسید آیا این مقدار را می‌توان مستقیماً از روی Props یا Stateهای دیگر که همین الان در دسترس هستند، محاسبه کرد؟ اگر پاسخ مثبت است، به آن State جداگانه نیازی نیست.

چند مثال دیگر از Derived State:

// به جای State جداگانه برای isEmpty
const isEmpty = items.length === 0;

// به جای State جداگانه برای fullName
const fullName = firstName + " " + lastName;

// به جای State جداگانه برای filteredList
const filteredList = items.filter((item) => item.active);

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

State واقعی زمانی لازم است که مقداری وجود دارد که نمی‌توان آن را از روی چیز دیگری در همان رندر محاسبه کرد؛ یعنی مقداری که خودش منبع اصلی اطلاعات است، نه نتیجه یک محاسبه. برای مثال، متنی که کاربر در یک input تایپ می‌کند، خودِ آن ورودی است، نه چیزی که از جای دیگری قابل‌محاسبه باشد؛ پس باید State باشد.

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

محاسبه مستقیم به‌جای State اضافی
برای دیدن پیش‌نمایش کامپوننت، روی Run بزنید.

جمع‌بندی

Derived State به مقادیری گفته می‌شود که می‌توان آن‌ها را مستقیماً از روی State یا Props موجود محاسبه کرد. تعریف State جداگانه برای چنین مقادیری، معمولاً باعث پیچیدگی اضافه، رندرهای غیرضروری و احتمال ناهماهنگی بین مقادیر می‌شود. قانون کلی این است: اگر مقداری قابل‌محاسبه است، برای آن State نسازید. در درس بعدی به مفهوم State Colocation می‌پردازیم.