Local State، Lifted State و Global State

در طول این دوره، با State در سطوح مختلفی کار کردیم: گاهی فقط داخل یک کامپوننت، گاهی بعد از Lifting State Up بین چند کامپوننت، و گاهی از طریق Context در سراسر برنامه. در این فصل، به‌طور مشخص به سراغ مدیریت State در مقیاس بزرگ می‌رویم؛ و این درس اول، سه سطح اصلی را که تا اینجا پراکنده دیده بودیم، کنار هم و با یک نام‌گذاری مشترک مرور می‌کند.

Local State: محدود به یک کامپوننت

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

jsx
function SearchBox() {
  const [query, setQuery] = useState("");
  return <input value={query} onChange={(e) => setQuery(e.target.value)} />;
}

همان‌طور که در فصل سوم درباره State Colocation دیدیم، این سطح باید پیش‌فرض اول باشد؛ تا وقتی مقداری فقط یک مصرف‌کننده دارد، نیازی به بالا بردنش نیست.

Lifted State: به اشتراک گذاشتن بین چند کامپوننت نزدیک

وقتی چند کامپوننت باید به یک مقدار مشترک دسترسی داشته باشند، در فصل سوم دیدیم که آن مقدار را به نزدیک‌ترین والد مشترک منتقل می‌کنیم:

jsx
function App() {
  const [selectedId, setSelectedId] = useState(null);
  return (
    <div>
      <ItemList selectedId={selectedId} onSelect={setSelectedId} />
      <ItemDetails selectedId={selectedId} />
    </div>
  );
}

این سطح، میانه راه بین Local و Global است: هنوز هم با Props منتقل می‌شود، اما دیگر محدود به یک کامپوننت واحد نیست.

Global State: در دسترس بخش‌های دور از هم برنامه

وقتی تعداد کامپوننت‌های مصرف‌کننده زیاد و پراکنده در سراسر درخت باشد، Lifting State Up به تنهایی ناکارآمد می‌شود؛ چون باید مقدار از لایه‌های زیادی عبور کند. همان‌طور که در فصل هشتم با Context دیدیم، در این حالت مقدار را در سطحی بالا قرار می‌دهیم که هر بخشی از برنامه، بدون Prop Drilling، به آن دسترسی داشته باشد.

jsx
const ThemeContext = createContext("light");

function App() {
  return (
    <ThemeContext.Provider value="dark">
      <EntireApp />
    </ThemeContext.Provider>
  );
}

این سه، یک طیف هستند، نه سه دسته جدا

نکته مهم این است که این سه سطح، مرزهای کاملاً مجزا نیستند؛ بلکه یک طیف‌اند بر اساس «چند کامپوننت، در چه فاصله‌ای از هم، به این مقدار نیاز دارند». یک State می‌تواند در طول توسعه یک برنامه، از Local شروع شود، بعد به یک والد نزدیک Lift شود، و اگر نیاز واقعی پیدا شد، نهایتاً به Global تبدیل شود. حرکت در این مسیر باید بر اساس نیاز واقعی باشد، نه این‌که از ابتدا هر State را Global تعریف کنیم.

چرا این تمایز، مقدمه این فصل است

در درس‌های بعدی این فصل، یک تمایز دیگر را هم کنار این سه سطح اضافه می‌کنیم: Client State در برابر Server State، که در فصل چهاردهم دیدیم. سپس می‌بینیم چه زمانی واقعاً به ابزار مدیریت State نیاز داریم، Trade-off های آن چیست، و اکوسیستم React چه گزینه‌هایی برای Global State ارائه می‌دهد.

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

در این مثال، هر سه سطح در کنار هم دیده می‌شوند: یک Local State داخل یک کامپوننت، یک State مشترک Lift‌شده بین دو کامپوننت، و یک مقدار Global از طریق Context.

سه سطح State در کنار هم
import { useState, createContext, useContext } from "react";

const ThemeContext = createContext("light");

function Hint() {
  const [visible, setVisible] = useState(false);
  return (
    <div>
      <button onClick={() => setVisible(!visible)}>نمایش راهنما (Local)</button>
      {visible && <p>این یک راهنمای محلی است.</p>}
    </div>
  );
}

function ItemList({ selectedId, onSelect }) {
  return (
    <div>
      <button onClick={() => onSelect("a")}>آیتم A</button>
      <button onClick={() => onSelect("b")}>آیتم B</button>
      <p>انتخاب‌شده (Lifted): {selectedId}</p>
    </div>
  );
}

function ThemeLabel() {
  const theme = useContext(ThemeContext);
  return <p>تم فعلی (Global): {theme}</p>;
}

function App() {
  const [selectedId, setSelectedId] = useState(null);

  return (
    <ThemeContext.Provider value="dark">
      <Hint />
      <ItemList selectedId={selectedId} onSelect={setSelectedId} />
      <ThemeLabel />
    </ThemeContext.Provider>
  );
}
برای دیدن پیش‌نمایش کامپوننت، روی Run بزنید.

جمع‌بندی

Local State فقط داخل یک کامپوننت زندگی می‌کند، Lifted State بین چند کامپوننت نزدیک با Props به اشتراک گذاشته می‌شود، و Global State از طریق ابزاری مثل Context، در سراسر برنامه قابل دسترسی است. این سه، یک طیف پیوسته‌اند که باید بر اساس نیاز واقعی و نه از پیش، انتخاب شوند. در درس بعدی، به تمایز Client State و Server State در همین زمینه مقیاس بزرگ برمی‌گردیم.