Lifting State Up: اشتراک‌گذاری State بین چند کامپوننت

در درس قبلی دیدیم که State باید تا حد امکان نزدیک به جایی باشد که استفاده می‌شود. اما گاهی چند کامپوننت مختلف، هرکدام واقعاً به یک مقدار مشترک نیاز دارند. در چنین حالتی، راه‌حل React الگویی به نام Lifting State Up است.

مشکل: دو کامپوننت که باید هماهنگ باشند

فرض کنید دو کامپوننت داریم: یکی یک لیست از آیتم‌ها نمایش می‌دهد و دیگری تعداد آیتم‌های انتخاب‌شده را نشان می‌دهد. اگر هرکدام State مستقل خودشان را داشته باشند، هیچ راهی برای هماهنگ نگه‌داشتن آن‌ها وجود ندارد؛ چون همان‌طور که در فصل اول دیدیم، هر نمونه از یک کامپوننت، State کاملاً جدا از نمونه‌های دیگر دارد.

// این دو کامپوننت هیچ راهی برای اشتراک داده ندارند
function ItemList() {
  const [selected, setSelected] = useState([]);
  // ...
}

function SelectedCount() {
  const [selected, setSelected] = useState([]);
  // این selected کاملاً جدا و بی‌ربط به بالایی است
}

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

برای اینکه دو یا چند کامپوننت بتوانند یک مقدار را با هم به اشتراک بگذارند، باید آن State را از داخل خودشان بیرون بیاوریم و در نزدیک‌ترین کامپوننت والد مشترکشان تعریف کنیم. سپس آن مقدار، و تابع تغییر آن، از طریق Props به هر دو کامپوننت فرزند داده می‌شود:

function App() {
  const [selected, setSelected] = useState([]);

  return (
    <div>
      <ItemList selected={selected} onToggle={setSelected} />
      <SelectedCount selected={selected} />
    </div>
  );
}

حالا هر دو کامپوننت به یک منبع واحد از داده دسترسی دارند؛ App به‌عنوان نزدیک‌ترین والد مشترک، مسئول نگهداری این State شده است.

چرا به آن Lifting «بالا بردن» می‌گویند

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

ارتباط با یک‌طرفه بودن جریان داده

در React، داده معمولاً به‌صورت یک‌طرفه از والد به فرزند جریان دارد (از طریق Props). Lifting State Up دقیقاً از همین اصل استفاده می‌کند: چون یک کامپوننت فرزند نمی‌تواند مستقیماً روی State کامپوننت دیگری اثر بگذارد، والد مشترک هم مقدار فعلی و هم راهی برای تغییر آن (یک تابع) را به فرزندان می‌دهد. به این ترتیب، همه تغییرات همچنان از یک منبع واحد و قابل‌پیش‌بینی عبور می‌کنند.

محدودیت این الگو در برنامه‌های بزرگ

وقتی تعداد کامپوننت‌هایی که باید به یک State دسترسی داشته باشند زیاد شود، یا وقتی این کامپوننت‌ها در سطوح خیلی متفاوتی از درخت کامپوننت قرار داشته باشند، انتقال مقدار و تابع تغییر آن از طریق چندین لایه Props می‌تواند دست‌وپاگیر شود. راه‌حل‌هایی برای این مشکل، مانند Context، در فصل‌های بعدی بررسی خواهند شد.

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

اشتراک‌گذاری State بین دو کامپوننت
برای دیدن پیش‌نمایش کامپوننت، روی Run بزنید.

جمع‌بندی

Lifting State Up یعنی انتقال State از کامپوننت‌های فرزندی که به یک مقدار مشترک نیاز دارند، به نزدیک‌ترین والد مشترک آن‌ها. این کار تنها زمانی لازم است که چند کامپوننت واقعاً باید با هم هماهنگ باشند، و همچنان باید در کنار اصل Colocation، یعنی بالا نبردن بیش از حد نیاز، به کار گرفته شود. با این درس، فصل سوم از نظر مفهومی به پایان می‌رسد و در ادامه به سراغ آزمون فصل ۳ می‌رویم.