UseLayoutEffect and useEffect have the same structure and function. The only difference is when they are called in the event loop.

Life cycles aside, event cycles are related to rendering

useEffect

UseEffect’s callback is an asynchronous macro task, which is executed in the next event loop. According to the principle of mutual exclusion between JS thread and GUI rendering thread, the rendering thread of the page in JS will execute the rendering thread only after the macro and micro tasks of the current event cycle are completed. After rendering the page, the rendering thread will exit, and the control will be handed over to JS thread, and then execute the next event cycle.

  1. Benefits: This makes it suitable for many common side effects scenarios, such as setting up subscriptions and event handling, because most actions should not block browser rendering updates to the screen.

  2. Cons: A second render problem occurs, the first rendering of the old state, and then in the next event loop, the function that changes the state is executed, and the component carries the new state rendering, which is visually a second render.

useLayoutEffect

UseLayoutEffect and componentDidMount, componentDidUpdate lifecycle hooks are asynchronous microtasks that are executed before the render thread is called. This means that the render page is not updated until the internal callback is executed, with no secondary render issues.

  1. Benefits: No secondary rendering issues, consistent page visual behavior.

  2. Cons: If there is some code or loop inside the callback that takes a long time to run, the page will be rendered to the renderer thread because it needs to wait for JS to finish executing.