«در React، دو ابزار اصلی برای بهینهسازی عملکرد و جلوگیری از رِندرهای اضافی داریم:
React.memoبرای کامپوننتهای تابعی وPureComponentبرای کامپوننتهای کلاسی.هر دو این ابزارها بر اساس یک اصل کار میکنند: «مقایسه سطحی» یا Shallow Compare. یعنی وقتی props یا state یک کامپوننت تغییر میکند، این ابزارها چک میکنند که آیا مقدار قبلی و جدید، در سطح اول (و نه عمیق) با هم تفاوت دارند یا نه. اگر تفاوتی نباشد، رِندر دوباره انجام نمیشود و عملکرد برنامه بهبود پیدا میکند.»
«برای درک Shallow Compare، یک مثال ساده بزنم:
اگر props ما یک
stringیاnumberباشد، مثلname="Ali"، مقدار قبلی و جدید مقایسه میشوند. اگر عوض شده باشد، رِندر جدید انجام میشود.اگر props ما یک آرایه یا ابجکت باشد، مثل
user={{ name: 'Ali', age: 30 }}، Shallow Compare فقط چک میکند که ارجاع (reference) آن ابجکت عوض شده است یا نه. یعنی اگر محتوای داخل ابجکت عوض شود اما خود ابجکت همان ابجکت قبلی باشد (همان reference)، تغییر تشخیص داده نمیشود و کامپوننت رِندر نمیشود.پس نتیجه مهم این است: اگر از
React.memoیاPureComponentاستفاده میکنیم، باید مواظب باشیم که props پیچیده (آرایه یا ابجکت) را بهصورت تغییرناپذیر (immutable) مدیریت کنیم. یعنی همیشه یک ابجکت یا آرایه جدید بسازیم، نه اینکه محتوای قبلی را تغییر دهیم.»**
«حالا تفاوتهای اصلی این دو را توضیح میدهم:
۱. نوع کامپوننت:
React.memoبرای کامپوننتهای تابعی استفاده میشود.
PureComponentبرای کامپوننتهای کلاسی استفاده میشود.۲. حوزه مقایسه:
React.memoفقط props را مقایسه میکند.
PureComponentهم props و هم state را مقایسه میکند.۳. کنترل دستی:
در
React.memoمیتوانیم یک تابع مقایسهکننده سفارشی (custom comparator) بهعنوان آرگومان دوم بدهیم تا دقیقاً مشخص کنیم چه زمانی رِندر انجام شود.در
PureComponentاین امکان بهصورت پیشفرض وجود ندارد و فقط از Shallow Compare استفاده میکند.۴. ارثبری:
PureComponentباshouldComponentUpdateکار میکند، در حالی کهReact.memoیک تابع مرتبهبالا (HOC) است که کامپوننت را میپیچد.»
«در Next.js که بر پایه React ساخته شده، دقیقاً همین قواعد برقرار است. اما یک نکته مهم در Next.js این است که:
در Server Components (که پیشفرض Next.js 13 به بالاست)، این بهینهسازیها معنی ندارند چون در سرور رندر میشوند و هیچ state یا effectی ندارند.
اما در Client Components که با
'use client'مشخص میشوند، دقیقاً مثل React معمولی ازReact.memoوPureComponentاستفاده میکنیم.پیشنهاد من در Next.js این است: تا جایی که ممکن است از Server Components استفاده کنیم و فقط بخشهای تعاملی را Client Component کنیم. در همان بخشهای کلاینت، اگر کامپوننتی props سنگین یا پیچیده دارد، از
React.memoبرای جلوگیری از رِندرهای اضافی استفاده میکنیم.»
«در کل، هدف از
React.memoوPureComponentبهبود عملکرد با جلوگیری از رِندرهای غیرضروری است. هر دو بر اساس Shallow Compare کار میکنند، اماReact.memoفقط برای کامپوننتهای تابعی و فقط روی props، وPureComponentبرای کلاسی و هم روی props و هم state. در Next.js هم این ابزارها فقط در Client Components کاربرد دارند و در Server Components نیازی به آنها نیست. مهمترین نکته این است که هنگام استفاده از آنها، همیشه دادههای پیچیده را بهصورت immutable مدیریت کنیم تا Shallow Compare درست کار کند.»
اگر از شما بپرسند «چه زمانی از React.memo استفاده نکنیم؟» میتوانید پاسخ دهید:
«اگر کامپوننتی props ساده یا تعداد کمی رِندر دارد، استفاده از
React.memoخودش هزینه اضافی دارد، چون خود مقایسه نیز زمانبر است. بنابراین فقط برای کامپوننتهای سنگین یا کامپوننتهایی که مرتباً رِندر میشوند ولی propsشان بهندرت تغییر میکند، از آن استفاده میکنم.»