مقدمه
React به صورت پیشفرض، با هر تغییر در state یا props یک کامپوننت را دوباره رندر میکند.
این یعنی تمام کدهای داخل تابع کامپوننت، در هر بار رندر مجدد، از نو اجرا میشوند. این رفتار
معمولاً مشکلی ایجاد نمیکند، اما اگر کامپوننت شما یک محاسبه سنگین و زمانبر را انجام دهد، اجرای
مکرر آن میتواند باعث کندی و لگ در رابط کاربری شود.
هوک useMemo یک ابزار بهینهسازی است که به ما اجازه میدهد تا نتیجه یک محاسبه را «به خاطر
بسپاریم» (memoize کنیم). useMemo نتیجه محاسبه را در حافظه کش کرده و تنها زمانی آن را دوباره
محاسبه میکند که یکی از وابستگیهای آن تغییر کرده باشد. در رندرهای دیگر، React به جای اجرای
مجدد محاسبه، از نتیجه کش شده استفاده خواهد کرد.
useMemo در عمل
هوک useMemo یک تابع (که محاسبه را انجام میدهد) و یک آرایه وابستگیها را به عنوان آرگومان
میگیرد.
یک مثال بدون بهینهسازی
بیایید یک کامپوننت بسازیم که یک تابع سنگین را فراخوانی میکند.
JAVASCRIPT (React)
function TodoList({ todos }) {
const [theme, setTheme] = useState('light');
const visibleTodos = filterTodos(todos, tab);
}
در این مثال، فرض کنید تابع filterTodos یک عملیات فیلتر کردن بسیار سنگین را روی یک لیست بزرگ از
todos انجام میدهد. مشکل اینجاست که حتی اگر کاربر تم (theme) را تغییر دهد (که هیچ ربطی به
لیست todos ندارد)، کامپوننت دوباره رندر شده و تابع سنگین filterTodos به صورت غیرضروری دوباره
اجرا میشود.
بهینهسازی با useMemo
حالا بیایید این محاسبه را با useMemo بهینه کنیم.
JAVASCRIPT (React)
import { useMemo } from 'react';
function TodoList({ todos, tab }) {
const [theme, setTheme] = useState('light');
const visibleTodos = useMemo(
() => filterTodos(todos, tab),
[todos, tab]
);
}
در این نسخه بهینهسازی شده، ما تابع filterTodos را در داخل یک useMemo قرار دادهایم. آرایه
وابستگیهای [todos, tab] به React میگوید که این محاسبه تنها به todos و tab وابسته است.
اکنون، اگر کاربر تم را تغییر دهد، کامپوننت دوباره رندر میشود، اما React میبیند که مقادیر
todos و tab تغییر نکردهاند. بنابراین، به جای اجرای مجدد تابع سنگین filterTodos نتیجه
قبلی آن را که در حافظه کش شده است، مستقیماً برمیگرداند.
چه زمانی از useMemo استفاده کنیم؟
مهم است به خاطر داشته باشید که useMemo خود نیز کمی هزینه سربار دارد. شما نباید هر تابعی را در
useMemo قرار دهید. useMemo را تنها برای موارد زیر به کار ببرید:
- محاسبات واقعاً سنگین: تنها محاسباتی را memoize کنید که اجرای آنها به طور قابل توجهی
زمانبر است.
- جلوگیری از رندرهای مجدد غیرضروری در کامپوننتهای فرزند: گاهی اوقات، شما یک شیء یا
آرایه را در داخل یک کامپوننت میسازید و آن را به عنوان prop به یک کامپوننت فرزند پاس
میدهید. اگر این کار را با useMemo بهینه نکنید، در هر بار رندر والد، یک شیء جدید ساخته شده
و باعث رندر مجدد غیرضروری فرزند میشود.
در این درس، با هوک useMemo به عنوان یک ابزار بهینهسازی قدرتمند برای جلوگیری از محاسبات تکراری
آشنا شدیم. دیدیم که چگونه میتوان با به خاطر سپردن نتایج محاسبات سنگین، عملکرد اپلیکیشنهای
React خود را بهبود بخشید. در درس بعدی، به سراغ یکی از قویترین الگوها در React، یعنی «طراحی
هوک سفارشی (Custom Hook)» خواهیم رفت و یاد میگیریم که چگونه منطق stateدار را بین کامپوننتهای
مختلف به اشتراک بگذاریم.