هوک useMemo در React Native نتیجه محاسبات را بین رندرهای کامپوننت مموریسازی میکند و از اجرای مجدد عملیاتهای پرهزینه جلوگیری مینماید. برخلاف useCallback که تابع را مموریسازی میکند، useMemo مقدار بازگشتی را ذخیره کرده و آن را فقط هنگام تغییر وابستگیهای مشخصشده مجدداً محاسبه میکند. طبق React Docs, 2024، مموریسازی بهویژه برای محاسبات با آرایههای بزرگ و تبدیلهای پیچیده داده مؤثر است. در React Native هر رندر مجدد اضافی بار اضافی بر اتصال پل بین جاوااسکریپت و تردهای بومی ایجاد میکند، بنابراین استفاده صحیح از useMemo مستقیماً بر روانی انیمیشنها و سرعت پاسخگویی رابط تأثیر میگذارد.
نکات کلیدی
useMemo — هوکی از کتابخانه استاندارد React است که در React Native بدون بستههای اضافی در دسترس میباشد. این هوک مقدار بازگشتی از تابع ارسالشده را مموریسازی کرده و این مقدار را در رندرهای بعدی تا زمانی که وابستگیهای مشخصشده در آرایه تغییر نکنند، مجدداً استفاده میکند.
نام هوک از کلمه انگلیسی memoization گرفته شده است — تکنیک بهینهسازی که در آن نتیجه یک تابع پرهزینه در کش ذخیره میشود. در فراخوانی مجدد با همان آرگومانها، به جای محاسبه مجدد، مقدار ذخیرهشده بازگردانده میشود.
در زمینه React Native مموریسازی به دلیل معماری خاص آن اهمیت ویژهای دارد. هر رندر مجدد کامپوننت دادهها را از طریق پل جاوااسکریپت — بومی ارسال میکند که زمانبر است. اگر کامپوننت شامل محاسبات پرهزینه (فیلتر کردن لیست، مرتبسازی، قالببندی) باشد، هر رندر مجدد آنها را تکرار کرده، ترد JS را مسدود کرده و باعث افت فریم میشود.
طبق React Native Performance Docs, 2024، تنگنا اغلب نه رندر کامپوننتهای بومی، بلکه اجرای منطق جاوااسکریپت بین رندرها است. useMemo دقیقاً همین مشکل را حل میکند.
useMemo یک تابع و یک آرایه وابستگی میپذیرد و مقدار مموریشده را بازمیگرداند. React مقدار قبلی و آرایه وابستگیها را ذخیره میکند. در هر رندر، React وابستگیهای جاری را با قبلی با استفاده از Object.is مقایسه میکند. اگر حداقل یک وابستگی تغییر کرده باشد، تابع دوباره اجرا شده و نتیجه ذخیره میشود.
امضای useMemo در وب و React Native کاملاً یکسان است. آرگومان اول — تابع بدون پارامتر که مقدار مموریشونده را بازمیگرداند. دوم — آرایه وابستگیها که با تغییر آنها مقدار مجدداً محاسبه خواهد شد.
import React, { useMemo } from 'react';
const sortedList = useMemo(() => {
return items.sort((a, b) => a.name.localeCompare(b.name));
}, [items]);
در این مثال sortedList فقط زمانی مجدداً محاسبه میشود که رفرنس آرایه items تغییر کند. اگر آرایه از نظر محتوا تغییر کرده باشد اما رفرنس ثابت مانده باشد (جهش)، useMemo تغییر را نخواهد دید — این یک محدودیت مهم است.
React برای مقایسه وابستگیها از الگوریتم Object.is استفاده میکند که مشابه برابری سختگیرانه === عمل میکند اما NaN را به درستی مدیریت میکند (+0 و -0 متفاوت در نظر گرفته میشوند). این بدان معناست که برای انواع اولیه (رشتهها، اعداد، بولینها) مقایسه بر اساس مقدار و برای اشیاء و آرایهها بر اساس رفرنس انجام میشود.
// Object.is({'a': 1}, {'a': 1}) -> false (ارجاعهای متفاوت)
// Object.is(42, 42) -> true (اولیه بر اساس مقدار)
// Object.is(NaN, NaN) -> true (مدیریت صحیح NaN)
درک این مکانیسم حیاتی است: اگر در هر رندر یک شیء جدید به وابستگیها ارسال شود، مموریسازی بیفایده خواهد بود، زیرا وابستگیها هر بار تغییر یافته تلقی میشوند.
useMemo در سه سناریو توجیهپذیر است: محاسبات پرهزینه، ارسال props پایدار به کامپوننتهای فرزند و حفظ هویت رفرنسی اشیاء. در React Native هر سه سناریو به دلیل ویژگیهای معماری برنامههای موبایل به طور منظم رخ میدهند.
اگر کامپوننت پردازش آرایههای داده بزرگ (فیلتر کردن، مرتبسازی، گروهبندی) یا عملیات ریاضی منابعبر را انجام میدهد، useMemo از تکرار این محاسبات در هر رندر مجدد جلوگیری میکند. در برنامههای موبایل مثال معمول — قالببندی دادههای API قبل از نمایش در لیست است.
وقتی کامپوننت فرزند در React.memo پیچیده شده است، فقط با تغییر props مجدداً رندر میشود. اگر شیء props در داخل والد بدون useMemo ایجاد شود، در هر رندر والد یک رفرنس جدید ایجاد شده و کامپوننت فرزند دوباره رندر میشود و فایده React.memo را از بین میبرد.
در React Native استایلها اغلب به props وابسته هستند — مثلاً عرض یک عنصر بر اساس اندازه صفحه محاسبه میشود. useMemo امکان محاسبه این استایلهای پویا را فقط هنگام تغییر پارامترهای ورودی فراهم میکند.
useMemo یک ابزار بهینهسازی جهانی نیست. در برخی سناریوها سودی ندارد و حتی ممکن است به دلیل سربار ذخیرهسازی و مقایسه وابستگیها عملکرد را بدتر کند. در React Native، جایی که هر بایت حافظه مهم است، استفاده کورکورانه از useMemo بدون اندازهگیری اثر، یک ضدالگو محسوب میشود.
هوک در سه مورد اصلی سودمند نیست. اول، اگر محاسبه ساده باشد (جمع ساده، الحاق رشتهها)، هزینههای useMemo از ارزش خود محاسبه فراتر میرود. دوم، اگر وابستگیها هر رندر تغییر کنند — تابع همچنان اجرا خواهد شد و مموریسازی فقط کار اضافی ایجاد میکند. سوم، اگر کامپوننت به ندرت رندر میشود، سربار ذخیرهسازی کش توجیهپذیر نیست.
طبق Kent C. Dodds, 2023، قبل از افزودن useMemo باید مشکل را با React DevTools Profiler یا Performance Monitor داخلی در React Native اندازهگیری کنید. اگر رندر مجدد کامپوننت کمتر از 1 میلیثانیه طول بکشد، مموریسازی لازم نیست.
useMemo و useCallback — دو هوک مموریسازی از React که اغلب اشتباه گرفته میشوند. تفاوت در این است که چه چیزی را ذخیره میکنند: useMemo نتیجه اجرای تابع (هر مقداری) را بازمیگرداند، در حالی که useCallback خود تابع را بازمیگرداند. هر دو آرایه وابستگی میپذیرند اما سینتکس متفاوت است.
| ویژگی | useMemo | useCallback |
|---|---|---|
| بازمیگرداند | نتیجه اجرای تابع | رفرنس به تابع |
| آرگومان اول | تابعی که مقدار بازمیگرداند | تابعی که باید مموریسازی شود |
| کاربرد معمول | کش کردن محاسبات | callbackهای پایدار برای کامپوننتهای فرزند |
| معادل | useMemo(() => fn, deps) | useCallback(fn, deps) === useMemo(() => fn, deps) |
در عمل useCallback — شکر نحوی بر روی useMemo برای مواردی است که نیاز به مموریسازی تابع داریم. در React Native هر دو هوک به یک اندازه استفاده میشوند: useMemo — برای دادهها (متن قالببندیشده، استایلهای محاسبهشده)، useCallback — برای handlerهای رویداد (onPress, onChangeText).
دو سناریوی واقعی استفاده از useMemo در برنامههای React Native را بررسی میکنیم. اولی — فیلتر کردن لیست مخاطبین بر اساس عبارت جستجو، دومی — محاسبه استایلهای پویا بر اساس اندازه صفحه.
در این مثال useMemo از فیلتر کردن مجدد لیست بزرگ مخاطبین در هر رندر جلوگیری میکند، اگر نه عبارت جستجو و نه دادههای منبع تغییر نکرده باشند.
const ContactList = ({ contacts, searchQuery }) => {
const filteredContacts = useMemo(() => {
if (!searchQuery.trim()) return contacts;
const query = searchQuery.toLowerCase();
return contacts.filter((c) =>
c.name.toLowerCase().includes(query) ||
c.phone.includes(query)
);
}, [contacts, searchQuery]);
return (
<FlatList
data={filteredContacts}
renderItem={renderContact}
keyExtractor={(item) => item.id}
/>
);
};
بدون useMemo فیلتر کردن در هر رندر اجرا میشد، از جمله رندرهای ناشی از انیمیشنها یا تغییر وضعیت سایر بخشهای کامپوننت. با useMemo فیلتر کردن فقط هنگام تغییر contacts یا searchQuery اجرا میشود.
در React Native استایلها اغلب به اندازههای صفحه یا props کامپوننت وابسته هستند. useMemo امکان محاسبه یکبار این شیء استایل و استفاده مجدد از آن را تا زمانی که وابستگیها تغییر نکنند فراهم میکند.
const Card = ({ title, isSelected }) => {
const cardStyle = useMemo(() => ({
backgroundColor: isSelected ? '#e3f2fd' : '#ffffff',
borderWidth: isSelected ? 2 : 1,
padding: 16,
}), [isSelected]);
return (
<View style={cardStyle}>
<Text>{title}</Text>
</View>
);
};
این رویکرد تضمین میکند که شیء cardStyle تا زمانی که isSelected تغییر نکند پایدار (همان رفرنس) باقی میماند. اگر Card در React.memo پیچیده شده باشد، این الگو از رندرهای مجدد غیرضروری عناصر فرزند جلوگیری میکند.
سوالات متداول
useMemo مقدار مموریشده را بازمیگرداند — نتیجه اجرای تابع ارسالشده به عنوان آرگومان اول. در رندرهای بعدی، React مقدار ذخیرهشده را بازمیگرداند اگر وابستگیها تغییر نکرده باشند.
useMemo نتیجه اجرای تابع را بازمیگرداند (هر مقداری: عدد، شیء، JSX)، در حالی که useCallback خود تابع را بازمیگرداند. همچنین useCallback(fn, deps) معادل useMemo(() => fn, deps) است.
useMemo در محاسبات ساده (جمع، الحاق)، رندرهای مجدد نادر، وابستگیهایی که در هر رندر تغییر میکنند و برای انواع اولیه بیفایده است. همیشه قبل از افزودن useMemo عملکرد را اندازهگیری کنید.
بله، اگر بدون نیاز استفاده شود. React مقادیر قبلی را در حافظه ذخیره میکند و در هر رندر وابستگیها را مقایسه میکند. برای محاسبات ساده، سربار این عملیات از سود مموریسازی بیشتر است.
از React DevTools Profiler برای اندازهگیری زمان رندر کامپوننتها استفاده کنید. در React Native همچنین Performance Monitor از طریق منوی توسعهدهنده در دسترس است. اگر رندر مجدد کمتر از 1 میلیثانیه طول بکشد — useMemo لازم نیست.
خلاصه
ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.
همچنین بخوانید