https://daveceddia.com/useeffect-vs-uselayouteffect/
The signature is identical to useEffect, but it fires synchronously after all DOM mutations. Use this to read layout from the DOM and synchronously re-render. Updates scheduled inside useLayoutEffect will be flushed synchronously, before the browser has a chance to paint.
Prefer the standard useEffect when possible to avoid blocking visual updates.
useLayoutEffect可以看作是useEffect的同步版本。使用useLayoutEffect就可以达到我们上面说的,在同一次更新流程中解绑interval的目的。
既然useLayoutEffect可以避免这个问题,那么为什么还要用useEffect呢,直接所有地方都用useLayoutEffect不就好了。
这个主要是因为useLayoutEffect是同步的,如果我们要在useLayoutEffect调用状态更新,或者执行一些非常耗时的计算,可能会导致React运行时间过长,阻塞了浏览器的渲染,导致一些卡顿的问题。
The Difference Between useEffect and useLayoutEffect
It’s all in the timing.
useEffect runs asynchronously and after a render is painted to the screen.
So that looks like:
-You cause a render somehow (change state, or the parent re-renders)
-React renders your component (calls it)
-The screen is visually updated
-THEN useEffect runs
useLayoutEffect, on the other hand, runs synchronously after a render but before the screen is updated. That goes:
-You cause a render somehow (change state, or the parent re-renders)
-React renders your component (calls it)
-useLayoutEffect runs, and React waits for it to finish.
-The screen is visually updated
Summary
useLayoutEffect:If you need to mutate the DOM and/ordo needto perform measurements
useEffect:If you don't need to interact with the DOM at all or your DOM changes are unobservable
The difference between useEffect and useLayoutEffect is in the time when the functions are invoked. To understand when the hooks are invoked it is helpful to understand that component re-render goes through the following steps. Let us assume we are implementing useEffect hook in our app.
1.User interacts with App. Let us say the user clicks a button.
2.Component state changes
3.The DOM is mutated
4.Changes are painted on the screen
5.cleanup function is invoked to clean effects from previous render if useEffect dependencies have changed.
6.useEffect hook is called after cleanup.
It should be noted that if a component is being rendered the first time, cleanup function is not invoked because there is no effect to clean up.
The difference between useEffect hook and useLayoutEffect hook is in the timing of their invocation. useEffect hook is invoked after the DOM is painted. useLayoutEffect hook on the other hand is invoked synchronously before changes are painted on the screen. The sequence of steps outlined above for useEffect implementation can be modified for useLayoutEffect as shown below:
1.User interacts with App. Let us say the user clicks a button.
2.Component state changes
3.The DOM is mutated
4.cleanup function is invoked to clean effects from previous render if useLayoutEffect dependencies have changed.
5.useLayoutEffect hook is called after cleanup.
6.Changes are painted on the screen
useEffect
The one catch is that this runs after react renders your component and ensures that your effect callback does not block browser painting. This differs from the behavior in class components where componentDidMount and componentDidUpdate run synchronously after rendering. It's more performant this way and most of the time this is what you want.
However, if your effect is mutating the DOM (via a DOM node ref) and the DOM mutation will change the appearance of the DOM node between the time that it is rendered and your effect mutates it, then you don't want to use useEffect. You'll want to use useLayoutEffect. Otherwise the user could see a flicker when your DOM mutations take effect. This is pretty much the only time you want to avoid useEffect and use useLayoutEffect instead.
-The function passed to useEffect fires after layout and paint. i.e after the render has been committed to the screen.
-This is okay for most side effects that should NOT block the browser from updating the screen.
-There are cases where you may not want the behaviour useEffect provides. e.g. if you need to make a visual change to the DOM as a side effect. To prevent the user from seeing flickers of changes, you may use useLayoutEffect.
-The function passed to useLayoutEffect will be run before the browser updates the screen.
useLayoutEffect
This runs synchronously immediately after React has performed all DOM mutations. This can be useful if you need to make DOM measurements (like getting the scroll position or other styles for an element) and then make DOM mutations or trigger a synchronous re-render by updating state.
As far as scheduling, this works the same way as componentDidMount and componentDidUpdate. Your code runs immediately after the DOM has been updated, but before the browser has had a chance to "paint" those changes (the user doesn't actually see the updates until after the browser has repainted).
When to useLayoutEffect
The right time to useLayoutEffect instead? You’ll know it when you see it. Literally ;)
If your component is flickering when state is updated – as in, it renders in a partially-ready state first and then immediately re-renders in its final state – that’s a good clue that it’s time to swap in useLayoutEffect.
This’ll be the case when your update is a 2-step (or multi-step) process. Do you want to “batch” a couple updates together before redrawing the screen? Try useLayoutEffect.
I think of useLayoutEffect as the way to squeeze in a little extra work before React updates the DOM. “Hey, you’re making some changes already – could you throw this one in there too? Awesome.”
Here’s a (contrived) example so you can see what I mean.
When you click the page*, the state changes immediately (value resets to 0), which re-renders the component, and then the effect runs – which sets the value to some random number, and re-renders again.
The result is that two renders happen in quick succession.
Try the useLayoutEffect version and then try the version with useEffect.
https://codesandbox.io/s/uselayouteffect-no-flash-ylyyg
https://codesandbox.io/s/useeffect-flash-on-render-yluoi
Notice how the version with useLayoutEffect only updates visually once even though the component rendered twice. The useEffect version, on the other hand, visually renders twice, so you see a flicker where the value is briefly 0.
Should I useEffect or useLayoutEffect?
Most of the time, useEffect is the right choice. If your code is causing flickering, switch to useLayoutEffect and see if that helps.
Because useLayoutEffect is synchronous a.k.a. blocking a.k.a. the app won’t visually update until your effect finishes running… it could cause performance issues like stuttering if you have slow code in your effect. Coupled with the fact that most effects don’t need the world to pause while they run, regular useEffect is almost always the one to use.
When do you choose useLayoutEffect over useEffect hook?
You can use useLayoutEffect hook instead of useEffect hook if your effect will mutate the DOM. useEffect hook is called after the screen is painted. Therefore mutating the DOM again immediately after the screen has been painted, will cause a flickering effect if the mutation is visible to the client.
useLayoutEffect hook on the other hand is called before the screen is painted but after the DOM has been mutated. The undesirable behavior, of mutating the DOM immediately after painting the screen, described with useEffect hook above can be avoided.
Though replacing useEffect hook with useLayoutEffect may not have a noticeable effect in simple apps, you are strongly advised against doing so (unless the situation warrants it) as stated here, to "avoid blocking visual effects". useLayoutEffect hook has its own use cases, so does useEffect hook. Read further about some use cases of useLayoutEffect at official react doc.
99% of the time, useEffect
Most of the time your effect will be synchronizing some bit of state or props with something that doesn’t need to happen IMMEDIATELY or that doesn’t affect the page visually.
Like if you’re fetching data, that’s not going to result in an immediate change.
Or if you’re setting up an event handler.
Or if you’re resetting some state when a modal dialog appears or disappears.
Most of the time, useEffect is the way to go.
One special case
One other situation you might want to use useLayoutEffect instead of useEffect is if you're updating a value (like a ref) and you want to make sure it's up-to-date before any other code runs. For example:
So in situations like that, the solution is useLayoutEffect.