Reconciliation و Identity: چگونه React تشخیص می‌دهد چه چیزی تغییر کرده

در درس قبل دیدیم React برنامه را به‌شکل یک درخت نگه می‌دارد. اما وقتی یک کامپوننت دوباره رندر می‌شود، React باید تصمیم بگیرد کدام گره‌های این درخت همان گره‌های قبلی هستند و کدام‌ها جدیدند. این فرایند تصمیم‌گیری، Reconciliation نام دارد و مفهومی به نام Identity در دل آن قرار دارد.

مسئله: مقایسه دو نسخه از یک درخت

بعد از هر Render، React یک درخت جدید از عناصر JSX دارد و باید آن را با درخت نسخه قبلی مقایسه کند تا بفهمد چه چیزی واقعاً عوض شده است. اگر React برای هر تغییر کوچک، کل DOM را از نو بسازد، هم عملکرد ضعیف می‌شود و هم چیزهایی مثل State داخلی هر کامپوننت یا فوکوس فعلی کاربر روی یک input از بین می‌رود. Reconciliation دقیقاً برای جلوگیری از این اتفاق طراحی شده است.

قانون اصلی: نوع و موقعیت، هویت یک گره را می‌سازند

React برای تطبیق دو نسخه از درخت، اصلی ساده اما مهم را دنبال می‌کند: اگر نوع عنصر (مثلاً div یا Counter) در یک موقعیت مشخص از درخت، در رندر جدید همان نوع رندر قبلی باشد، React آن را «همان گره قبلی» در نظر می‌گیرد؛ نه یک نمونه جدید.

// رندر اول
<div>
  <Counter />
</div>

// رندر دوم
<div>
  <Counter />
</div>

در این دو رندر، Counter در همان موقعیت (فرزند اول همان div) با همان نوع باقی مانده است؛ پس React همان نمونه قبلی را حفظ می‌کند و State داخلی Counter از بین نمی‌رود.

وقتی نوع عوض شود، Identity هم عوض می‌شود

اگر در همان موقعیت از درخت، نوع عنصر بین دو رندر فرق کند، React نتیجه می‌گیرد گره قدیمی از بین رفته و یک گره کاملاً جدید جایگزینش شده است؛ حتی اگر ظاهراً شبیه هم باشند:

// رندر اول
<Counter />

// رندر دوم
<FancyCounter />

در این حالت، React اول نمونه قدیمی Counter را کاملاً حذف می‌کند (و State آن از بین می‌رود)، سپس FancyCounter را از صفر می‌سازد. این رفتار حتی وقتی رخ می‌دهد که یک شرط ساده، نوع عنصر رندرشده را در همان محل عوض کند، موضوعی که با جزئیات بیشتر در فصل دوازدهم بررسی می‌شود.

Identity فقط درباره نوع و موقعیت است، نه محتوای Props

نکته‌ای که گاهی باعث سردرگمی می‌شود این است که تغییر Props یک کامپوننت، هویت آن را عوض نمی‌کند. اگر نوع و موقعیت یکسان بماند، React همان نمونه را نگه می‌دارد و فقط Props جدید را به آن می‌دهد؛ حتی اگر مقدار Props کاملاً متفاوت باشد.

<UserBadge name="سارا" />
// بعداً، در همان موقعیت:
<UserBadge name="علی" />

در این مثال، همان نمونه UserBadge باقی می‌ماند و فقط Prop name تغییر می‌کند؛ اگر این کامپوننت خودش State داخلی داشته باشد، آن State هم حفظ می‌شود.

چرا این مدل، همان چیزی است که پشت Keyها هست

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

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

در این مثال، با تغییر شرط، نوع کامپوننت رندرشده در همان موقعیت عوض می‌شود و State آن از بین می‌رود؛ روی دکمه‌های افزایش و تعویض کلیک کنید تا این رفتار را ببینید.

از بین رفتن State با تغییر نوع کامپوننت در یک موقعیت
برای دیدن پیش‌نمایش کامپوننت، روی Run بزنید.

جمع‌بندی

Reconciliation یعنی مقایسه دو نسخه از Component Tree برای تشخیص تغییرات واقعی؛ و در این مقایسه، Identity یک گره از روی نوع و موقعیتش در درخت تعیین می‌شود، نه از روی مقدار Props. اگر نوع و موقعیت ثابت بماند، همان نمونه با State آن حفظ می‌شود؛ در غیر این صورت، یک نمونه کاملاً تازه ساخته می‌شود. در درس بعدی به نقش دقیق‌تر Keyها در همین فرایند می‌پردازیم.