حتما یکی از پروژهامو انتقال میدم به تایپ ۷ و نتیجه بیلد قبل و بعدش رو میزارم براتون
❤2
👀 یه سوال ساده :
اگه یه کامپوننت رو با
جواب کوتاه : نه همیشه.
نتیجه؟ memo هیچ کاری نمیکنه و کامپوننت بازم رندر میشه.
راهحلش اینه که خود رفرنس رو ثابت نگه دارین، نه اینکه فقط فرزند رو memoize کنین. برای function از
منبع رسمی
اگه یه کامپوننت رو با
React.memo بپیچونید، مطمئنین دیگه بیخودی رندر نمیشه؟جواب کوتاه : نه همیشه.
React.memo فقط پراپها رو با === مقایسه میکنه. حالا اگه یکی از پراپهاتون یه object یا function باشه که هر بار توی parent از نو ساخته میشه، از نظر رفرنس با دفعه قبل فرق داره — حتی اگه محتواش عین هم باشه.نتیجه؟ memo هیچ کاری نمیکنه و کامپوننت بازم رندر میشه.
راهحلش اینه که خود رفرنس رو ثابت نگه دارین، نه اینکه فقط فرزند رو memoize کنین. برای function از
useCallback و برای object/array از useMemo کمک بگیرین.منبع رسمی
👍2🔥1
⚡️ نکته سریع امروز
یه function رو بین رندرها ثابت نگه میداره،
در واقع هر دو زیر hood یه چیزن.
نکتهای که خیلیا ازش غافلن :
اگه یه محاسبه سنگین نیست و صرفاً یه رشته یا عدد سادهست، اصلاً نیازی به
قانون کلی : فقط وقتی استفاده کنین که یا محاسبه واقعاً سنگینه، یا میخواید رفرنس رو برای memo کردن یه فرزند ثابت نگه دارین.
⚠️ یه نکته جانبی هم بگم
اگه پروژهتون داره از React Compiler استفاده میکنه، عملا نیازی به useMemo و useCallback دستی ندارین کامپایلر خودش تحلیل میکنه کجا باید memoize بشه و خودکار اعمال میکنه — دقیقتر از چیزی که ما دستی مینویسیم.
ولی واقعیت اینه که اکثر پروژههای production هنوز روی React 18 هستن و کامپایلر رو adopt نکردن. پس دونستن این مفاهیم هنوزم ضروریه.
useMemo
useCallback
reactCompiler
useCallbackیه function رو بین رندرها ثابت نگه میداره،
useMemo یه مقدار محاسبهشده رو (object، array، عدد سنگین).در واقع هر دو زیر hood یه چیزن.
useCallback(fn, deps) دقیقاً معادله با useMemo(() => fn, deps).نکتهای که خیلیا ازش غافلن :
اگه یه محاسبه سنگین نیست و صرفاً یه رشته یا عدد سادهست، اصلاً نیازی به
useMemo نیست. هزینه خود hook (نگهداشتن dependency array و مقایسهش) گاهی از خود محاسبه گرونتره.قانون کلی : فقط وقتی استفاده کنین که یا محاسبه واقعاً سنگینه، یا میخواید رفرنس رو برای memo کردن یه فرزند ثابت نگه دارین.
⚠️ یه نکته جانبی هم بگم
اگه پروژهتون داره از React Compiler استفاده میکنه، عملا نیازی به useMemo و useCallback دستی ندارین کامپایلر خودش تحلیل میکنه کجا باید memoize بشه و خودکار اعمال میکنه — دقیقتر از چیزی که ما دستی مینویسیم.
ولی واقعیت اینه که اکثر پروژههای production هنوز روی React 18 هستن و کامپایلر رو adopt نکردن. پس دونستن این مفاهیم هنوزم ضروریه.
useMemo
useCallback
reactCompiler
🔥2
🚀 روی یه پروژه واقعی کار میکردم که LCPش رو ۳.۲ ثانیه بود. الان رو ۰.۹ ثانیهست. بگم چیکار کردیم؟
سه تا تصمیم بیشترین تاثیر رو داشت :
۱. فونت
فونت اختصاصی پروژه باعث میشد صفحه یه مدت کاملاً سفید بمونه (FOIT). با
۲. تصویر Hero
تصویر Hero که خودش عنصر LCP بود، با
۳. Code splitting هدفمند
lazy import کردن همه چیز اشتباهه. کامپوننتهای above-the-fold رو static گذاشتیم، فقط چیزایی که پایین صفحه بودن (مودالها و...) رو dynamic کردیم.
Optimize LCP
next/image
سه تا تصمیم بیشترین تاثیر رو داشت :
۱. فونت
فونت اختصاصی پروژه باعث میشد صفحه یه مدت کاملاً سفید بمونه (FOIT). با
display: swap و preload کردن فایل فونت، مرورگر اول با فونت fallback رندر میکنه و بعد جایگزین میکنه. همین یه چیز، حدود ۶۰۰ میلیثانیه از رندر اول کم کرد.۲. تصویر Hero
تصویر Hero که خودش عنصر LCP بود، با
loading="lazy" بارگذاری میشد! یعنی مرورگر دیرتر از حد لازم میرفت سراغش. یه priority گذاشتیم روش و تموم شد.۳. Code splitting هدفمند
lazy import کردن همه چیز اشتباهه. کامپوننتهای above-the-fold رو static گذاشتیم، فقط چیزایی که پایین صفحه بودن (مودالها و...) رو dynamic کردیم.
Optimize LCP
next/image
❤3💯2👌1
Foad Labs
👀 یه سوال ساده : اگه یه کامپوننت رو با React.memo بپیچونید، مطمئنین دیگه بیخودی رندر نمیشه؟ جواب کوتاه : نه همیشه. React.memo فقط پراپها رو با === مقایسه میکنه. حالا اگه یکی از پراپهاتون یه object یا function باشه که هر بار توی parent از نو ساخته میشه،…
📌 تکمیل پست قبلی درباره React.memo
بعد از انتشار این پست توی لینکدین، یکی از دوستان یه نکته خوب رو یادآوری کرد که بد نیست بهش اشاره کنیم.
اول اینکه React.memo در واقع پراپها رو با Object.is مقایسه میکنه، نه صرفا ===. تفاوتش تو اکثر سناریوها ناچیزه، اما از نظر فنی این همون مکانیزمیه که React استفاده میکنه.
نکته دوم و مهمتر اینکه React.memo یه پارامتر اختیاری به اسم arePropsEqual داره. با این تابع میتونین خودتون مشخص کنین که دو سری پراپ چه زمانی «برابر» محسوب بشن.
مثلا فرض کنین از API هر بار یه آبجکت جدید دریافت میکنین :
const UserCard = React.memo(
UserCardComponent,
(prevProps, nextProps) => prevProps.user.id === nextProps.user.id
);
توی این حالت، حتی اگه رفرنس آبجکت عوض شده باشه، تا وقتی id تغییر نکرده باشه، کامپوننت دوباره رندر نمیشه.
اما یه نکته مهم 👇
arePropsEqual
قرار نیست جای useMemo و useCallback رو بگیره. اگر والد هر بار object یا function جدید بسازه، بهتره اول دلیلش رو برطرف کنین و رفرنسها رو پایدار نگه دارین. نوشتن مقایسهی سفارشی برای هر کامپوننت هم هزینه نگهداری داره و اگر اشتباه پیادهسازی بشه، حتی میتونه باعث باگ بشه.
خلاصه اینکه:
✅ React.memo
برای جلوگیری از رندرهای غیرضروری مفیده.
✅ useMemo و useCallback
برای ثابت نگه داشتن رفرنسها هستن.
✅ arePropsEqual
هم ابزاریه برای سناریوهای خاص، نه راهحل پیشفرض.
بهینهسازی توی React بیشتر از اینکه حفظ کردن هوکها باشه، درک نحوهی مقایسهی پراپها و جریان رندر شدنه.
بعد از انتشار این پست توی لینکدین، یکی از دوستان یه نکته خوب رو یادآوری کرد که بد نیست بهش اشاره کنیم.
اول اینکه React.memo در واقع پراپها رو با Object.is مقایسه میکنه، نه صرفا ===. تفاوتش تو اکثر سناریوها ناچیزه، اما از نظر فنی این همون مکانیزمیه که React استفاده میکنه.
نکته دوم و مهمتر اینکه React.memo یه پارامتر اختیاری به اسم arePropsEqual داره. با این تابع میتونین خودتون مشخص کنین که دو سری پراپ چه زمانی «برابر» محسوب بشن.
مثلا فرض کنین از API هر بار یه آبجکت جدید دریافت میکنین :
const UserCard = React.memo(
UserCardComponent,
(prevProps, nextProps) => prevProps.user.id === nextProps.user.id
);
توی این حالت، حتی اگه رفرنس آبجکت عوض شده باشه، تا وقتی id تغییر نکرده باشه، کامپوننت دوباره رندر نمیشه.
اما یه نکته مهم 👇
arePropsEqual
قرار نیست جای useMemo و useCallback رو بگیره. اگر والد هر بار object یا function جدید بسازه، بهتره اول دلیلش رو برطرف کنین و رفرنسها رو پایدار نگه دارین. نوشتن مقایسهی سفارشی برای هر کامپوننت هم هزینه نگهداری داره و اگر اشتباه پیادهسازی بشه، حتی میتونه باعث باگ بشه.
خلاصه اینکه:
✅ React.memo
برای جلوگیری از رندرهای غیرضروری مفیده.
✅ useMemo و useCallback
برای ثابت نگه داشتن رفرنسها هستن.
✅ arePropsEqual
هم ابزاریه برای سناریوهای خاص، نه راهحل پیشفرض.
بهینهسازی توی React بیشتر از اینکه حفظ کردن هوکها باشه، درک نحوهی مقایسهی پراپها و جریان رندر شدنه.
🔥1
🤔 این دوتا یه مسئله رو حل میکنن ولی فلسفهشون کاملاً فرق داره.
🔄 Redux Toolkit
هنوز به slice و reducer نیاز داره. حتی با RTK، ساختار قابل پیشبینیه ولی حجیمتره.
📦 Zustand
با یه تابع create، کل store رو میسازه، بدون Provider اجباری، بدون boilerplate اضافه.
⚡️ از نظر re-render هم هر دو با selector کار میکنن، پس اونجا فرقی نیست.
🎯 سوال اصلی اینه : تیم چندنفرهاین و به قوانین سختگیرانه و DevTools پیشرفته نیاز دارین؟ ← Redux Toolkit 🛠️
پروژۀ کوچیک تا متوسطه و سرعت توسعه اولویته؟ ← Zustand 🚀
منابع :
🔗 Zustand — Getting Started
🔗 Redux Toolkit — Quick Start
🔄 Redux Toolkit
هنوز به slice و reducer نیاز داره. حتی با RTK، ساختار قابل پیشبینیه ولی حجیمتره.
📦 Zustand
با یه تابع create، کل store رو میسازه، بدون Provider اجباری، بدون boilerplate اضافه.
⚡️ از نظر re-render هم هر دو با selector کار میکنن، پس اونجا فرقی نیست.
🎯 سوال اصلی اینه : تیم چندنفرهاین و به قوانین سختگیرانه و DevTools پیشرفته نیاز دارین؟ ← Redux Toolkit 🛠️
پروژۀ کوچیک تا متوسطه و سرعت توسعه اولویته؟ ← Zustand 🚀
منابع :
🔗 Zustand — Getting Started
🔗 Redux Toolkit — Quick Start
🔥2
⚙️ اکثر پیادهسازیهای useDebounce که توی پروژههای مختلف دیدم، یه مشکل مشترک دارن :
کلینآپ ندارن!
بدون cleanup، هر بار که ورودی عوض میشه، تایمر قبلی هنوز فعاله و ممکنه callback قدیمی با state قدیمی اجرا بشه (stale closure).
دو نکته مهم :
همیشه generic تعریفش کنید تا برای هر نوع داده قابل استفاده مجدد باشه
delay
رو حتما توی dependency array بذارید وگرنه اگه تغییر کنه، hook متوجه نمیشه
منبع رسمی
کلینآپ ندارن!
بدون cleanup، هر بار که ورودی عوض میشه، تایمر قبلی هنوز فعاله و ممکنه callback قدیمی با state قدیمی اجرا بشه (stale closure).
دو نکته مهم :
همیشه generic تعریفش کنید تا برای هر نوع داده قابل استفاده مجدد باشه
delay
رو حتما توی dependency array بذارید وگرنه اگه تغییر کنه، hook متوجه نمیشه
منبع رسمی
👌2
🔴 چالش امشب
این کد یه infinite loop تولید میکنه خودتون دلیلش رو پیدا کنین
15 دقیقه دیگه جوابش رو میزارم همراه با راهحل
#Labs_Challenge
این کد یه infinite loop تولید میکنه خودتون دلیلش رو پیدا کنین
15 دقیقه دیگه جوابش رو میزارم همراه با راهحل
#Labs_Challenge
🔥1
جواب :
هر بار توی کامپوننت از نو ساخته میشه (یه object literal جدید)، پس رفرنسش هر رندر عوض میشه،
🟠 برای حل این مشکل سه تا راهحل داریم که توی تصویر ذکر شده
🟢 بهترین راهحل به context و منطق کامپوننتتون ستگی داره. اگه
options هر بار توی کامپوننت از نو ساخته میشه (یه object literal جدید)، پس رفرنسش هر رندر عوض میشه،
useEffect دوباره اجرا میشه، یه رندر جدید اتفاق میفته... و این چرخه هیچوقت تموم نمیشه.🟠 برای حل این مشکل سه تا راهحل داریم که توی تصویر ذکر شده
🟢 بهترین راهحل به context و منطق کامپوننتتون ستگی داره. اگه
options ثابته، گزینه ۳ بهترینه چون اصلا هیچ هزینهای نداره.🔥1
مرسی از همه دوستان که توی چالش امشب شرکت کردن و نظرات خودشونو درمیون گذاشتن
فردا کلی محتوا و در آخرشب هم چالش داریم
شبتون پر از ایدههای میلیون دلاری 😁❤️
فردا کلی محتوا و در آخرشب هم چالش داریم
شبتون پر از ایدههای میلیون دلاری 😁❤️
🔥1
امروز رو اختصاص میدیم به خود Next.js و rendering strategies توی اون
مثل همیشه خوشحال میشیم نظرات و فکرهایی که به ذهنتون میاد رو با بقیه به اشتراک بزارین تا کنار همدیگه رشد کنیم ❤️
برو بریم
مثل همیشه خوشحال میشیم نظرات و فکرهایی که به ذهنتون میاد رو با بقیه به اشتراک بزارین تا کنار همدیگه رشد کنیم ❤️
برو بریم
🔥1
⁉️ یه سوال که توی هر مصاحبه فرانتاند پرسیده میشه
فرق SSR، SSG و ISR چیه؟
بذارین خیلی ساده توضیح بدم
1️⃣ SSG — Static Site Generation
صفحه موقع build یه بار ساخته میشه و همون سرو میشه به همه. سریعترین حالت ممکنه چون فایل آمادهست.
🟢 مناسب برای : صفحه About، بلاگ، صفحات ثابت
2️⃣ SSR — Server-Side Rendering
هر بار که کاربر درخواست میده، سرور HTML رو از نو میسازه.
🟢 مناسب برای : داشبورد، صفحاتی که دادهشون هر لحظه عوض میشه
3️⃣ ISR — Incremental Static Regeneration
بین دوتای قبلی قرار میگیره. HTML استاتیکه، ولی بعد از یه بازه زمانی مشخص پشت صحنه دوباره ساخته میشه — بدون اینکه کاربر منتظر بمونه.
🟢 مناسب برای : صفحه محصولات، اخبار، هر چیزی که دادهش تغییر میکنه ولی real-time نیست
انتخاب درست بین این سه، مستقیم روی TTFB (time to first byte) و هزینه سرور تاثیر میذاره.
منبع رسمی :
Fetching Data
Rendering Strategies
فرق SSR، SSG و ISR چیه؟
بذارین خیلی ساده توضیح بدم
1️⃣ SSG — Static Site Generation
صفحه موقع build یه بار ساخته میشه و همون سرو میشه به همه. سریعترین حالت ممکنه چون فایل آمادهست.
🟢 مناسب برای : صفحه About، بلاگ، صفحات ثابت
2️⃣ SSR — Server-Side Rendering
هر بار که کاربر درخواست میده، سرور HTML رو از نو میسازه.
🟢 مناسب برای : داشبورد، صفحاتی که دادهشون هر لحظه عوض میشه
3️⃣ ISR — Incremental Static Regeneration
بین دوتای قبلی قرار میگیره. HTML استاتیکه، ولی بعد از یه بازه زمانی مشخص پشت صحنه دوباره ساخته میشه — بدون اینکه کاربر منتظر بمونه.
// هر یک ساعت یه بار regenerate میشه
export const revalidate = 3600;
🟢 مناسب برای : صفحه محصولات، اخبار، هر چیزی که دادهش تغییر میکنه ولی real-time نیست
انتخاب درست بین این سه، مستقیم روی TTFB (time to first byte) و هزینه سرور تاثیر میذاره.
منبع رسمی :
Fetching Data
Rendering Strategies
❤2
⚡️ Server Components vs Client Components
کجا مرز رو بکشیم؟ 🤔
یکی از رایجترین اشتباهها توی Next.js اینه که
قانون ساده 📜 :
Server Component
بمونه اگه :
- فقط داده نمایش میده
- به API یا دیتابیس وصله
- هیچ تعاملی با کاربر نداره (کلیک، فرم، state)
Client Component
بشه اگه :
- از
- به event listener نیاز داره
- از browser API استفاده میکنه
🛑 اشتباه رایج :
منبع رسمی :
Server and Client Components
کجا مرز رو بکشیم؟ 🤔
یکی از رایجترین اشتباهها توی Next.js اینه که
use client رو بالای کامپوننتهایی میذارن که اصلا نیازی ندارن.قانون ساده 📜 :
Server Component
بمونه اگه :
- فقط داده نمایش میده
- به API یا دیتابیس وصله
- هیچ تعاملی با کاربر نداره (کلیک، فرم، state)
Client Component
بشه اگه :
- از
useState یا useEffect استفاده میکنه- به event listener نیاز داره
- از browser API استفاده میکنه
🛑 اشتباه رایج :
'use client' گذاشتن روی layout یا page اصلی. این یعنی کل درخت کامپوننت client-side میشه و مزیت Server Components از بین میره.منبع رسمی :
Server and Client Components
👍1
⏱️ صفحمون TTFB بالای 2 ثانیه داشت اما Streaming SSR رو حل کرد
❗️ مشکل اینجا بود که صفحه منتظر میموند تا همه دیتاها از سه تا endpoint جدا برگردن، بعد HTML رو میفرستاد. کاربر تا اون موقع فقط یه صفحه سفید میدید.
این رو بهش میگن waterfall مشکلدار :
درخواست کاربر
کاربر ۲.۸ ثانیه صبر میکنه تا اولین pixel ببینه.
🟢 راهحل : هر کامپوننت داده خودش رو مستقل fetch کنه (عکس ضمیمه شده)
الان timeline اینشکلیه :
درخواست کاربر
کاربر بعد از ۳۰۰ms یه صفحه معنادار میبینه، نه ۲.۸ ثانیه صفحه سفید، تفاوت رو دیدین ؟
⚠️ یه نکته مهم :
loading.tsx توی Next.js fallback کل route رو مدیریت میکنه، ولی Suspense بهتون کنترل دقیقتر میده — میتونید بخشهای مختلف یه صفحه رو جداگانه هندل کنین
منبع رسمی :
Fetching Data#Streaming
Granular streaming with Suspense
Streaming
❗️ مشکل اینجا بود که صفحه منتظر میموند تا همه دیتاها از سه تا endpoint جدا برگردن، بعد HTML رو میفرستاد. کاربر تا اون موقع فقط یه صفحه سفید میدید.
این رو بهش میگن waterfall مشکلدار :
درخواست کاربر
↓ fetchUser() → 300ms
↓ fetchPosts() → 500ms
↓ fetchComments() → 2000ms 😬
↓ HTML آماده میشه و میره سمت کاربر
کاربر ۲.۸ ثانیه صبر میکنه تا اولین pixel ببینه.
🟢 راهحل : هر کامپوننت داده خودش رو مستقل fetch کنه (عکس ضمیمه شده)
الان timeline اینشکلیه :
درخواست کاربر
↓ همه fetchها موازی شروع میشن
↓ UserCard → 300ms ✅ فوری نمایش
↓ Posts → 500ms ✅ skeleton، بعد محتوا
↓ Comments → 2000ms ✅ skeleton، بعد محتوا
کاربر بعد از ۳۰۰ms یه صفحه معنادار میبینه، نه ۲.۸ ثانیه صفحه سفید، تفاوت رو دیدین ؟
⚠️ یه نکته مهم :
loading.tsx توی Next.js fallback کل route رو مدیریت میکنه، ولی Suspense بهتون کنترل دقیقتر میده — میتونید بخشهای مختلف یه صفحه رو جداگانه هندل کنین
منبع رسمی :
Fetching Data#Streaming
Granular streaming with Suspense
Streaming
❤2
Foad Labs
🔴 چالش شب — Next.js 🟠 چالش اصلاح میشه
من معذرت میخام دوستان کانتکست چالش اشتباه گذاشته شده
اصلاح شدش رو براتون میزارم امشب و تا فردا مثل همیشه نظراتتون رو بگین و شرکت کنین توی چالش ❤️
اصلاح شدش رو براتون میزارم امشب و تا فردا مثل همیشه نظراتتون رو بگین و شرکت کنین توی چالش ❤️
❤1