دیاگ ری-اکت - بهبود پرفومنس رندر شدن کامپوننت ها

ما یه سری کامپوننت داشتیم که فهمیدنشون کار مشکلی بود. از طرفی به خاطر لاجیک پیچیده ای که داشتن از اینکه تغییرشون بدیم هم می‌ترسیدیم. این شد که گفتیم بهتره یه تایم خوبی رو اختصاص بدیم که اینا رو ریفکتور کنیم. هدف اینکار هم ساده تر شدن API های کامپوننت بود هم بهبود پرفورمنس.اولین قدم برای همچین کاری اینه که دقیق و کامل متوجه باشیم که اون کامپوننت داره چه کاری انجام میده که بعد از ریفکتور کردن چیزی از قلم نیوفته. بنابراین یه بار دیگه نیازمندی های پروداکت ریویو شد و با چیزی که تا اون زمان پیاده شده بود بررسی انجام شد.برای مثال من یه اسکرین شات از دیجی کالا میذارم.به عنوان مثال توی این تصویر از سمت راست کاربر میتونه Variation مورد نظر خودش رو انتخاب کنه و بعد از تغییر Variant قیمت ممکنه تغییر کنه. در هر صورت امکان اینکه هر کالا چند فروشنده و هر فروشنده قیمت خودش رو داشته باشه وجود داره.حالا اتفاقی که اینجا میتونه بیوفته اینه که بعد از هر بار انتخاب کاربر، پردازش دیتا ها انجام بشه و قیمت مشخص بشه، و راه حل بعد این هست بار اولی که دیتا ها از سمت سرور دریافت میشن یکبار برای همه ی Variatoin ها این پردازش یکبار انجام بشه و با تغییر Variant این پردازش ها تکرار نشن.اینکه کدوم یک از این ۲ روش بهتر هستند کاملا بستگی به شرایط داره ولی برای ما راه حل دوم بهتر جواب میداد. پس نکته اول برای بهبود این فرایند برای ما بردن پردازش ها یک جای دیگه و استفاده کردن ازش توی کامپوننت بود به جای اینکه بار هر بار کلیک کاربر این اتفاق بیوفته.تعداد Rerenderمرحله بعد کم کردن تعداد Render شدن کامپوننت بود. اولین قدم اینه که بفهمیم این کامپوننت چند بار داره رندر میشه، فهمیدن این موضوع خیلی ساده میتونه به کمک console.count انجام بشه. به این صورت که توی بدنه کامپوننت (بدنه اصلی کامپوننت) یه دونه console.count قرار بدید و ببینید چند بار اجرا میشه. توی این کیس خاص ممکنه شما همچین چیزی رو ببینید:همینطور که مشخصه ۱۵ بار داره اجرا میشهاین یعنی وضعیت اصلا خوب نیست. اگر این نتیجه ای هست که بعد از لود شدن صفحه میبینید (بدون اینکه interaction ای انجام بدید) باید یه قدمی برای بهبود دادنش بردارید.اولین کاری که انجام دادم این بود که به جای استفاده از useEffect برای اینکه ببینم دیتا لود شده یا نه از callback هایی که خود useSWR بهمون میده استفاده کردم. درسته مورد خیلی خیلی ساده و پیش پا افتاده ای بود ولی تاثیر خیلی خوبی گذاشت. از طرف دیگه مهمه که بدونیم Side effect های هوک هایی که استفاده می کنیم چی هستن و آیا منجر به رندر شدن مجدد صفحه میشن یا نه. توی بررسی هایی که انجام شد کلی از این موارد پیدا شد که عملا Redundant state بودن و به هیچ دردی نمیخوردن (البته نه به همین راحتی ولی میشد براشون جایگزین های کم هزینه تری پیدا کرد). برای همین شروع کردم به ریفکتور کردن و حذف کردن اون state ها و استفاده از چیز های دیگه.به عنوان مثال، جایی بود که یه کامپوننت داشت با Javascript ساخته میشد و پوزیشن اش ست میشد و بعد که داخلش رفتم دیدم میشه کلش رو فقط با CSS هندل کرد.سرعت رندر شدنتوی این فرایند کلی کامپوننت دیدیم که با وجودی که Prop هاشون هیچ تغییری نمیکرد هیچوقت، ولی memoize نشده بودن. بنابراین اگر توی کامپوننت والد اونها چیزی تغییر میکرد این کامپوننت ها هم مجدد رندر میشدن. بنابراین ساده ترین راه حل برای اینکار استفاده کردن از React.memo بود که در واقع کامپوننت اش رو Pure کنیم.موضوع مهم دیگه این بود که توی بعضی از کامپوننت ها هر بار که Rerender می‌شد (میدونیم که هربار رندر شدن کامپوننت یعنی اجرای کل کامپوننت از بالا تا پایین) یه پردازش سنگینی اتفاق میوفتاد. مجدد برای اینکه این مشکل حل بشه از هوک useMemo استفاده کردیم.سوال مهم تری که اینجا مطرح میشه اینه که چطور این موارد رو اندازه گیری کنیم که ببینیم آیا باید براش اکشنی برداریم یا نه.استفاده از Profiler و console.timeاگر میخوایم سرعت رندر شدن کامپوننت ها رو اندازه گیری کنیم، طبق داکیومنت خود React یک HOC به تعبیه شده به اسم Profiler که میتونه براتون سرعت رندر شدن کامپوننت ها (و البته کلی چیز دیگه) رو اندازه گیری کنه. استفاده کردن ازش خیلی سادس: https://gist.github.com/hesan-aminiloo/f84a0ac1dba451b6b5f9dac54aecf6ff خب استفاده از Profiler به همین سادگی هست که می‌بینید. از شما یه id میخواد که یه شناسه میدید بهش و زمانی که صفحه رو لود کنید روی کنسول ممکنه همچین چیزی رو ببینید:خب این داره بهتون میگه که توی کدوم فاز از رندر (روی mount یا update مثلا) چقدر طول کشیده که اون کامپوننت با آیدی خاصی که شما بهش دادید، رندر بشه. طبیعتا هر چقدر زمان بیشتری طول بکشه یعنی کامپوننت شما سنگین تره.این برای این بود که متوجه بشیم کامپوننت ها چه پرفورمنسی دارن، ولی برای اینکه ببینیم مثلا یه تابع یا پردازش توی بدنه کامپوننت یه یه تابع دیگه چقدر طول می کشه میتونیم از console.time و console.timeEnd استفاده کنیم. مثلا: https://gist.github.com/hesan-aminiloo/06a129270d4052c99dd8580cdd8a7741 پس به کمک همین تکنیک ساده هم میتونیم بفهمیم که چقدر طول می کشه که این محاسبه انجام بشه. مثالی که من آوردم خیلی خیلی ساده اس ولی امیدوارم ایده رو گرفته باشید.جمع بندی کنماولین چیزی که از خودتون باید بپرسید اینه که هدفتون در نهایت چیه و میخواید از کجا به کجا برید. بعد سعی کنیم مسائل رو ریز کنید به قسمت های کوچک تر و بعد هر کدوم رو جدا برای خودش حل کنید. استفاده از ابزار ها خیلی خوبه ولی اگر ندونید که دارید چیکار میکنید ممکنه همونا بیشتر باعث دردسرتون بشن.یادتون نره که بعد از تغییرات حسابی تست کنید و مطمئن بشید که همه چیز داره درست کار میکنه.توی بهبود دادن پرفورمنس رندر شدن ری-اکت، پر اهمیت ترین موضوع هندل کردن side-effect هایی هست که شما شاید حتی ندونید که اونا وجود دارن. پس اولین قدمی که برمیدارید این باید باشه که اونها رو پیدا کنید و به حداقل برسونید شون و بعد برید سراغ اینکه سرعت رندر شدن رو بالا ببرید چون ممکنه تحت هیچ شرایطی نتونید تعداد رندر ها رو کم کنید ولی لااقل هزینه شون رو کمتر کنید.میدونیم که قطعا ابزار های باحالی هستن که میتونیم ازشون برای مانیتور کردن و بهبود دادن فرایند کار کردن خودمون ازشون استفاده کنیم، من صرفا تجربه ای که خودم داشتم و روش هایی که خودم استفاده کردم رو بهشون اشاره کردم، این به این معنی نیست که استفاده از اون ابزار ها رو تایید یا رد میکنم.دمتون گرم - اگه دوس داشتید میتونید از طریق Linkedin باهام در ارتباط باشید