useEffect در مقابل useLayoutEffect
۱۴۰۳/۱۱/۲۲
این مقاله، ترجمهای است از مقالهی اصلی به نام useEffect vs useLayoutEffect که توسط Kent C. Dodds نوشته شده است.
اساسا از هر دو این موارد میتوان برای یک کار مشابه استفاده کرد، اما موارد استفاده آنها کمی با هم تفاوت دارند. بنابراین اینجا به قوانینی میپردازیم که بتوانیم تصمیم بگیریم از کدام هوک React استفاده کنیم.
useEffect
۹۹ درصد مواقع این همون چیزی هست که باید استفاده کنید. از زمانی که هوکها جا افتادن و stable شدن و احیانا شما هم وقتی خواستید class componentهای خودتون رو با هوکها بازنویسی کنید، احتمالاً کدهای مربوط به componentDidMount
، componentDidUpdate
و componentWillUnmount
رو به useEffect
منتقل کردید.
نکتهای که وجود داره اینه که این هوک بعد از رندر شدن کامپوننت توسط React اجرا میشه و اطمینان میده که کالبک effect باعث مسدود شدن رندر مرورگر نمیشه. این رفتار با class componentها متفاوت هست، چون در اونها componentDidMount
و componentDidUpdate
به صورت همزمان بعد از رندر اجرا میشن. این روش کارایی بهتری داره و در اکثر مواقع چیزی هست که میخواید.
با این حال، اگر افکت شما (از طریق یک ref) تغییری در DOM ایجاد کند و این تغییرات باعث شود ظاهر گ ره (node) DOM بین زمان رندر و اجرای افکت تغییر کند، در این صورت نباید از useEffect
استفاده کنید. در این شرایط باید از useLayoutEffect
استفاده کنید. در غیر این صورت، کاربر ممکن است یک فلیکر (تغییر ناگهانی ظاهر) را هنگام اعمال تغییرات DOM مشاهده کند. میشه گفت این تقریباً تنها زمانی هست که باید از useEffect اجتناب کنید و به جای آن از useLayoutEffect
استفاده کنید.
useLayoutEffect
این هوک به صورت همزمان و بلافاصله پس از انجام تمام تغییرات DOM توسط React اجرا میشود. این ویژگی میتواند زمانی مفید باشد که نیاز دارید اندازهگیریهایی از DOM (مانند گرفتن موقعیت اسکرول یا استایلهای دیگر برای یک المنت) انجام دهید و سپس تغییرات DOM را اعمال کرده یا با بروزرسانی state، رندر همزمان مجدد ایجاد کنید.
از نظر زمانبندی، این عملکرد مشابه componentDidMount
و componentDidUpdate
است. کد شما بلافاصله پس از بروزرسانی DOM اجرا میشود، اما قبل از این که مرورگر فرصت داشته باشد تا تغییرات را "رندر" (paint) کند (کاربر تغییرات را تا زمانی که مرورگر آنها را دوباره رندر نکرده باشد، نمیبیند).
خلاصه
- useLayoutEffect: اگر نیاز دارید که DOM را تغییر دهید و/یا اندازهگیریهایی انجام دهید.
- useEffect: اگر نیازی به تعامل با DOM ندارید یا تغییرات DOM شما قابل مشاهده نیستند (در واقع، بیشتر مواقع باید از این استفاده کنید).
یک مورد خاص
یک موقعیت دیگر که ممکن است لازم باشد از useLayoutEffect
به جای useEffect
استفاده کنید زمانی است که در حال بروزرسانی یک مقدار (مانند یک ref
) هستید و میخواهید اطمینان حاصل کنید که قبل از اجرای هر کد دیگری، مقدار بهروز شده است. برای مثال:
const ref = React.useRef()
React.useEffect(() => {
ref.current = 'some value'
})
// then, later in another hook or something
React.useLayoutEffect(() => {
console.log(ref.current) // <-- this logs an old value because this runs first!
})
پس در چنین موقعیتهایی، راهحل استفاده از useLayoutEffect
است.
نتیجهگیری
موضوع اصلی در مورد پیشفرضها است. رفتار پیشفرض این است که به مرورگر اجازه داده میشود قبل از اجرای کد شما توسط React، بر اساس بهروزرسانیهای DOM دوباره رندر کند. این بدین معناست که کد شما مانع عملکرد مرورگر نمیشود و کاربر تغییرات DOM را سریعتر مشاهده میکند. بنابراین، در بیشتر مواقع بهتر است از useEffect
استفاده کنید.