نقش دقیق Keyها در Rendering

در درس قبل دیدیم که React هویت یک گره را از روی نوع و موقعیت آن در درخت تشخیص می‌دهد، و در فصل اول به‌طور مختصر گفتیم که Key به React کمک می‌کند آیتم‌های یک لیست را ردیابی کند. در این درس، این دو موضوع را کنار هم می‌گذاریم و دقیقاً می‌بینیم Key چه نقشی در فرایند Reconciliation دارد.

مشکل: موقعیت در آرایه، هویت پایداری نیست

فرض کنید لیستی از وظایف داریم و بدون Key، آن‌ها را رندر می‌کنیم:

function TaskList({ tasks }) {
  return (
    <ul>
      {tasks.map((task) => (
        <li>{task.text}</li>
      ))}
    </ul>
  );
}

بدون key، React به‌ناچار فقط از روی موقعیت هر آیتم در آرایه تصمیم می‌گیرد کدام li همان li قبلی است. اگر یک آیتم از وسط لیست حذف شود، همه آیتم‌های بعد از آن، یک موقعیت به بالا می‌آیند؛ و از دید React، انگار محتوای هرکدام از آن موقعیت‌ها عوض شده، نه اینکه یک آیتم واقعاً حذف شده باشد.

Key: هویتی مستقل از موقعیت

با دادن یک key پایدار به هر آیتم، به React می‌گوییم هویت واقعی این عنصر را از روی این مقدار بشناس، نه از روی جایگاهش در آرایه:

function TaskList({ tasks }) {
  return (
    <ul>
      {tasks.map((task) => (
        <li key={task.id}>{task.text}</li>
      ))}
    </ul>
  );
}

حالا اگر آیتمی با id="t2" از وسط لیست حذف شود، React دقیقاً می‌فهمد کدام گره باید از DOM حذف شود و بقیه آیتم‌ها، همراه با State داخلی‌شان (اگر داشته باشند)، دست‌نخورده باقی می‌مانند؛ فقط ترتیب نمایش عوض می‌شود.

Key، هویت را جایگزین موقعیت می‌کند، نه چیز دیگری

دقیقاً همان قاعده Identity که در درس قبل دیدیم، اینجا هم برقرار است؛ فقط با یک تفاوت: به‌جای اینکه React از موقعیت خام در والد استفاده کند، از ترکیب key برای تشخیص «همان گره قبلی بودن» یا «گره تازه بودن» استفاده می‌کند. اگر یک key در رندر جدید دیگر در لیست نباشد، React آن گره را کاملاً حذف می‌کند، حتی اگر آیتم دیگری با محتوای مشابه در همان موقعیت ظاهری باشد.

اثر عملی روی State هر آیتم

وقتی هر آیتم لیست خودش یک کامپوننت با State داخلی است، انتخاب درست Key اهمیت بیشتری پیدا می‌کند. برای مثال، اگر هر آیتم یک فیلد ویرایش‌پذیر داشته باشد، Key نادرست می‌تواند باعث شود مقدار وارد‌شده در یک ردیف، بعد از تغییر ترتیب لیست، به‌اشتباه در ردیف دیگری ظاهر شود؛ چون React همان گره DOM را برای یک آیتم متفاوت دوباره استفاده کرده است. جزئیات بیشتر این رفتار و راه‌حل‌هایش، موضوع فصل بعدی، درباره حفظ و بازنشانی State، است.

یادآوری: چرا index معمولاً Key خوبی نیست

همان دلیلی که در فصل اول اشاره کردیم، حالا روشن‌تر است: استفاده از index به‌عنوان Key، عملاً یعنی دوباره به همان موقعیت خام در آرایه برگردیم؛ همان چیزی که Key قرار بود جایگزینش شود. به همین دلیل، وقتی ترتیب یا تعداد آیتم‌ها ممکن است تغییر کند، یک شناسه پایدار و مرتبط با خود داده (مانند id)، انتخاب درست‌تری است.

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

در این مثال، هر آیتم یک فیلد قابل ویرایش دارد. یک آیتم را ویرایش کنید، سپس آیتم اول را حذف کنید و ببینید مقدار ویرایش‌شده همراه با آیتم درست باقی می‌ماند، چون از id به‌عنوان Key استفاده شده است.

حفظ صحیح State هر ردیف با key پایدار
برای دیدن پیش‌نمایش کامپوننت، روی Run بزنید.

جمع‌بندی

Key به React اجازه می‌دهد هویت هر عنصر یک لیست را مستقل از موقعیتش در آرایه تشخیص دهد؛ همین چیز باعث می‌شود حذف، افزودن یا جابه‌جایی آیتم‌ها، به‌درستی روی DOM و State هر آیتم اعمال شود. استفاده از index به‌جای یک شناسه پایدار، عملاً همان مشکل موقعیت خام را بازمی‌گرداند. در درس بعدی به این می‌پردازیم که دقیقاً چه چیزی باعث Re-render یک کامپوننت می‌شود.