درود دوستان 👋 میخوایم دو هوک ریاکتی رو با هم مقایسه کنیم که توی اسم و ظاهر خیلی شبیه به هم هستن. اما کاربرهای منحصر به فردی دارن. این پست از مجموعه پستهای ریاکت ۱۰۱ هست که شامل مجموعهای از پستهای کوتاه و کاربردی ریاکتی میشه.
useEffect چیه؟
این هوک که احتمالاً خیلی بیشتر با اون آشنایی دارین، برای مدیریت Side Effect ها توی یک کامپوننت ریاکت به کار میره. منظور از Side Effect اتفاقهایی هست که میخوایم بعد از رخ دادن یک رویداد توی کامپوننت انجام بشه. مثلاً وقتی که مقدار یک استیت بروز میشه، یا وقتی که کامپوننت برای اولین بار رندر میشه و میخوایم API Call انجام بدیم. احتمالاً با نحوهٔ پیادهسازی این هوک آشنایی دارین، بنابراین از این قسمت صرف نظر کنیم.
useLayoutEffect چیه؟
این هوک یک هوک خاص توی ریاکت هست و کاربردهای محدودتر و منحصر به فردی داره؛ گرچه این هوک هم مثل useEffect برای مدیریت کردن Side Effect ها به کار میره و نحوهٔ پیادهسازی مشابهی داره:
useLayoutEffect(() => { // Do Side Effects }, []);
همونطور که میبینیم این هوک هم یک کالبک و یک آرایه برای تعریف Dependency ها میگیره. چیزی که این دو هوک رو از هم متمایز میکنه، نحوه و زمان اجرای اون کالبکی هست که تعریف کردیم.
تفاوتهای این دو هوک
وقتی تغییری توی DOM رخ میده، بعد از اون، مرحلهای وجود داره به اسم Painting مرورگر که مرورگر باید تغییرات رو توی صفحه نمایش بده. به عبارت دیگه، منظور از Painting مرورگر، زمانی هست که تغییری توی DOM صورت گرفته و مرورگر میخواد اون تغییرات رو نشون بده. به این عملیات گفته میشه Painting.
تفاوت اول
اولین تفاوت مهم این دو هوک اینه که توی useLayoutEffect کالبک مد نظر ما بعد از تغییر توی DOM و از عملیات Painting اجرا میشه. در صورتی که useEffect کار مد نظر ما از عملیات Painting اجرا میکنه.
تفاوت دوم
دومین تفاوت مهم اینه که useLayoutEffect کالبک ما رو به صورت Synchronous اجرا میکنه و بنابراین Render Blocking هست و تا زمانی که اجرای اون کالبک تموم نشده عملیات بعدی از جمله Painting مرورگر قابل اجرا شدن نیستن. بر خلاف useEffect که اجرای کالبک اون Async هست و باعث بلاک شدن کامپوننت نمیشه.
کد زیر یک نمونه از زمانی هست که این هوک باعث بلاک شدن کامپوننت میشه:
export default function App() { const [count, setCount] = useState(0); useLayoutEffect(() => { const now = performance.now(); while (performance.now() - now < 2000) {} }); return ( <div> <h1>Count: {count}</h1> <button onClick={() => setCount((prev) => prev + 1)}>Increment</button> </div> ); }
