درود دوستان 👋 میخوایم تابعی رو توی ریاکت بررسی کنیم به اسم memo() که استفاده از اون ممکنه خیلی کاربردی و جذاب به نظر بیاد، اما نکتهها و بایدها و نبایدهایی داره بهتره قبل از استفاده اونها رو بدونیم. این پست از مجموعه پستهای ریاکت ۱۰۱ هست که شامل مجموعهای از پستهای کوتاه و کاربردی ریاکتی میشه.
تابع memo() چیه؟ 🤔
memo یک Higher-order Function هست که یک کامپوننت رو میگیره و حالت بهینهشدهٔ اون رو تحویل میده. به بیان فنیتر، این تابع برای Memoize کردن (به خاطر سپردن) خروجی یک کامپوننت به کار میره. توی این حالت، کامپوننت فقط زمانی ری-رندر میشه که Prop های اون تغییر کنه:
import { memo } from 'react'; function MyComponent(props) { // ... return ( <>...</> ); } const Memoized = <<memo(MyComponent)>>; export default Memoized;
گرچه این ویژگی خیلی قدرتمندی به حساب میاد و کمک میکنه از رندرهای اضافی جلوگیری کنیم، اما قبل از استفاده از اون باید نکتههایی رو به خاطر بسپاریم که توی ادامه اونها رو بررسی میکنیم.
چه زمانی از memo استفاده کنیم؟
توی ادامه میخوایم شرایطی رو بررسی کنیم که استفاده از memo پیشنهاد میشه.
۱. کامپوننت دارای رندرهای سنگین
یکی از شرایطی که استفاده از memo خیلی اهمیت پیدا میکنه شرایطی هست که کامپوننت ما دارای رندر خیلی پیچیده و سنگینی هست و هر بار رندر شدن اون هزینهٔ قابل ملاحظهای داره. بنابراین استفاده از memo ترفند هوشمندانهای به حساب میاد.
۲. کامپوننتی که دفعات زیادی در معرض ری-رندر هست
همونطور که گفتیم memo زمانی از رندر اضافی جلوگیری میکنه که پراپرتیهای کامپوننت تغییر نکنه. و اگه کامپوننتی داریم که در معرض رندرهای زیاد هست (مثل تغییر توی کامپوننت والدِ اون که در نتیجه باعث رندر شدن مجدد کامپوننتهای داخلی میشه،) اگه پراپرتیهای اون بدون تغییر باقی میمونه بهتره که از memo استفاده کنیم تا از رندرهای اضافی جلوگیری کنیم.
خب حالا میخوایم موضوع مهم این پست رو بررسی کنیم، یعنی:
چه زمانی از memo استفاده نکنیم؟
باید بدونیم که استفاده از memo بی هزینه هم نیست و استفاده از اون توی شرایطی ممکنه نتایج معکوس بده و بجای افزایش بهینگی، پیچیدگی و افت سرعت و باگهای ناشناخته دریافت کنیم.
۱. وقتی که کامپوننت خیلی ساده هست
وقتی کامپوننتهای خیلی کوچیک داریم که رندر شدن اونها خیلی ساده هست، استفاده از memo با توجه به محاسباتی که انجام میده فشار بیشتری رو به برنامه متحمل میکنه. بنابراین استفاده از memo توی چنین شرایطی توصیه نمیشه.
۲. وقتی پراپهای کامپوننت مدام تغییر میکنه
همونطور که میدونیم آبجکتها و توابع Reference Values هستن و با مقادیر Primitive مثل عدد و رشته فرق میکنن. پس وقتی به یک کامپوننت پراپرتیهایی از نوع آبجکت یا تابع پاس بدیم، تابع memo نمیتونه یکسان بودن اون پراپرتیها رو تضمین کنه و در نتیجه کامپوننت ری-رندر میشه (توی روی دکمه کلیک کنید و کنسول رو ببینید) مگر اینکه پراپرتیهای پاس داده شده تغییر نکنن و دقیقاً همون مقادیر قبلی پاس داده بشن (مثل استفاده از useMemo و useCallback توی کامپوننتهای والد.)
function MyComponent() { const data = { ... }; const callBack = () => { ... }; return ( <Child data={data} callback={callBack} /> ); }
توی کد بالا استفاده از memo توی کامپوننت Child یک کار بیهوده به حساب میاد. چون با هر بار رندر شدن کامپوننت والد، مقادیر data و callBack مقادیر قبلی نیستن (رفرنس اونها فرق میکنه) و در نتیجه کامپوننت Child هم رندر میشه. مگر اینکه از useMemo و useCallback استفاده کنیم:
function MyComponent() { const data = useMemo(() => ({ ... }, []); const callBack = useCallback(() => { ... }, []); return ( <Child data={data} callback={callBack} /> ); }
کد بالا شاید مشکل ما رو حل کنه، اما استفاده نادرست از useMemo و useCallback هم مثل بقیه تکنیکهای بهینهسازی ممکنه راه حل مناسبی به حساب نیاد. توی پستهای بعدی بایدها و نبایدهای استفاده از این دو تابع رو هم بررسی خواهیم کرد.
گرچه تابع memo قابلیتی داره که به ما اجازه میده عمل مقایسه رو خودمون انجام بدیم. مثلاً توی شرایط بالا میتونیم برای مقایسه آبجکتها Shallow Compare انجام بدیم.
۳. وقتی کامپوننت به یک Context وابسته هست
وقتی کامپوننت ما به یک کانتکست وابسته هست و یا استیتهای درونی اون تغییر میکنن، با تغییر کانتکست یا استیت، کامپوننت هم ری-رندر میشه و تابع memo عملاً کاربردی نداره.
خب دوستان به پایان این پست رسیدیم. موضوع Optimization توی هر برنامهای یک شمشیر دو لبه هست و استفاده بیرویه از تکنیکهای بهینهسازی، نه تنها باعث بهبود کیفیت برنامه نمیشه، بلکه گاهی نتیجهٔ عکس داره و ممکنه کاهش کیفیت و سرعت برنامه و سختتر شدن روند توسعهٔ اون میشه. امیدوارم از مطالبی که بررسی کردیم استفاده کرده باشین. تا یه پست دیگه روزتون خوش 😉👋
