چه چیزی باعث Re-render یک کامپوننت می‌شود

در طول این فصل، چند بار درباره اینکه «یک کامپوننت دوباره رندر می‌شود» صحبت کردیم، بدون اینکه دقیقاً فهرست کنیم چه اتفاقاتی باعث این رندر مجدد می‌شوند. در این درس، سه دلیل اصلی Re-render را با هم مرور می‌کنیم.

دلیل اول: تغییر State خود کامپوننت

رایج‌ترین دلیل، فراخوانی یک تابع set از useState یا dispatch از useReducer است. با هر تغییر واقعی در State (مقداری که با مقدار قبلی برابر نیست)، React همان کامپوننت را دوباره Render می‌کند.

function Counter() {
  const [count, setCount] = useState(0);
  return <button onClick={() => setCount(count + 1)}>{count}</button>;
}

دلیل دوم: رندر مجدد کامپوننت والد

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

function App() {
  const [theme, setTheme] = useState("light");
  return (
    <div>
      <ThemeButton onClick={() => setTheme("dark")} />
      <StaticFooter />
    </div>
  );
}

در این کد، با تغییر theme، StaticFooter هم دوباره Render می‌شود، حتی اگر هیچ Propی نگیرد و همیشه یک خروجی ثابت داشته باشد. این رفتار خودش یک انتخاب طراحی عمدی در React است: بدون بررسی این‌که آیا Render مجدد واقعاً لازم است یا نه، React همه فرزندان را دوباره محاسبه می‌کند، و بعد در مرحله Commit تصمیم می‌گیرد چه چیزی واقعاً باید در DOM تغییر کند.

دلیل سوم: تغییر مقدار Context

همان‌طور که در فصل هشتم دیدیم، تغییر value یک Provider، باعث Render دوباره تمام کامپوننت‌هایی می‌شود که از همان Context با useContext استفاده می‌کنند؛ صرف‌نظر از اینکه آن کامپوننت‌ها در کدام شاخه از درخت باشند و چه فاصله‌ای با Provider داشته باشند.

چیزهایی که به‌تنهایی باعث Re-render نمی‌شوند

چند نکته مهم که گاهی محل اشتباه است:

  • تغییر مقدار current یک useRef، همان‌طور که در فصل هفتم دیدیم، هرگز باعث Render مجدد نمی‌شود.
  • فراخوانی set با مقداری دقیقاً برابر با مقدار فعلی State، React را وادار به Render مجدد آن کامپوننت نمی‌کند.
  • تغییر یک متغیر معمولی جاوااسکریپت (بدون useState)، همان‌طور که در فصل سوم دیدیم، هیچ اثری روی رندر ندارد.

چرا شناخت این فهرست مفید است

وقتی متوجه شدیم بخشی از برنامه بیشتر از حد انتظار دوباره Render می‌شود، این فهرست کمک می‌کند مسیر را ردیابی کنیم: آیا خود این کامپوننت State دارد که تغییر می‌کند؟ آیا یکی از والدینش دارد بی‌دلیل Render می‌شود؟ یا از یک Context وابسته است که مقدارش مدام عوض می‌شود؟ ابزارهایی برای کاهش Render‌های غیرضروری ناشی از والد، مانند React.memo، موضوع فصل سیزدهم خواهند بود.

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

مشاهده Re-render فرزند در پی تغییر State والد
برای دیدن پیش‌نمایش کامپوننت، روی Run بزنید.

جمع‌بندی

سه دلیل اصلی Re-render عبارت‌اند از: تغییر State خود کامپوننت، Render شدن کامپوننت والد (که به‌طور پیش‌فرض کل زیردرخت را دوباره Render می‌کند)، و تغییر مقدار یک Context که کامپوننت از آن استفاده می‌کند. تغییر Ref، تغییر متغیر معمولی، یا فراخوانی set با همان مقدار قبلی، هیچ‌کدام به‌تنهایی این اثر را ندارند. در درس بعدی، کل جریان یک به‌روزرسانی را از ابتدا تا انتها تحلیل می‌کنیم.