Keyها و Identity: کنترل دستی هویت یک کامپوننت

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

key فقط مخصوص لیست‌ها نیست

در فصل یازدهم دیدیم key به React کمک می‌کند آیتم‌های یک آرایه را مستقل از موقعیتشان ردیابی کند. اما همین ایده روی هر عنصر JSX، حتی خارج از لیست، قابل استفاده است: key بخشی از هویت یک عنصر می‌شود، در کنار نوع و موقعیت آن.

مشکل: یک کامپوننت که باید با تغییر داده، از نو شروع شود

فرض کنید یک فرم بازخورد داریم که برای هر کاربر جداگانه نمایش داده می‌شود، اما اگر کاربر عوض شود، می‌خواهیم فیلد نظر خالی شود، نه اینکه نظر کاربر قبلی باقی بماند:

function FeedbackForm({ userId }) {
  const [note, setNote] = useState("");
  return <textarea value={note} onChange={(e) => setNote(e.target.value)} />;
}

function App() {
  const [userId, setUserId] = useState("u1");
  return <FeedbackForm userId={userId} />;
}

با تغییر userId، طبق قاعده Reconciliation، نوع و موقعیت FeedbackForm ثابت مانده؛ پس React همان نمونه را حفظ می‌کند و note از کاربر قبلی باقی می‌ماند؛ رفتاری که در این مورد خاص، اصلاً مطلوب نیست.

راه‌حل: دادن key متفاوت برای اجبار به بازنشانی

با دادن یک key که به userId وابسته است، React را وادار می‌کنیم هر بار که userId عوض می‌شود، یک نمونه کاملاً جدید بسازد:

function App() {
  const [userId, setUserId] = useState("u1");
  return <FeedbackForm key={userId} userId={userId} />;
}

حالا با تغییر userId، از دید React این «همان کامپوننت با هویت متفاوت» است؛ نمونه قدیمی حذف می‌شود، State آن از بین می‌رود و یک FeedbackForm کاملاً تازه، با note خالی، ساخته می‌شود.

key یعنی «این هویت متفاوتی دارد»، نه یک شناسه فنی صرف

دیدگاه درست این است که key پاسخ به این سؤال است: «آیا این باید همان چیز قبلی در نظر گرفته شود یا یک چیز جدید؟» وقتی از نظر مفهومی، یک کامپوننت با تغییر یک مقدار باید کاملاً از نو شروع شود (مثل فرم بازخورد بالا)، همان مقدار، انتخاب طبیعی برای key است.

یک اثر جانبی مفید: اجرای دوباره State اولیه و Effectها

وقتی با تغییر key، یک نمونه جدید ساخته می‌شود، این یعنی از دید React، کامپوننت قبلی Unmount و کامپوننت جدید Mount شده است. در نتیجه، مقدار اولیه State دوباره از صفر محاسبه می‌شود و تمام Effectهایی که با آرایه خالی نوشته شده بودند، دوباره اجرا می‌شوند؛ درست مثل اولین باری که کامپوننت روی صفحه ظاهر می‌شود.

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

در این مثال، بدون key، متن فرم بین کاربران باقی می‌ماند. یک متن بنویسید، کاربر را عوض کنید و ببینید چه اتفاقی می‌افتد؛ سپس در کد key اضافه‌شده را بررسی کنید.

بازنشانی State با تغییر key بر اساس userId
برای دیدن پیش‌نمایش کامپوننت، روی Run بزنید.

جمع‌بندی

key بخشی از هویت یک عنصر است، نه فقط ابزاری برای لیست‌ها؛ با دادن key متفاوت به یک کامپوننت در همان موقعیت، React را وادار می‌کنیم آن را نمونه‌ای کاملاً جدید در نظر بگیرد و State قبلی را کنار بگذارد. این تکنیک وقتی مفید است که تغییر یک مقدار، از نظر مفهومی، باید باعث شروعی تازه شود. در درس بعدی، به‌طور مستقیم‌تر به State Preservation می‌پردازیم.