Is `useLayoutEffect` preferable to `useEffect` when reading layout? - reactjs

One difference about useLayoutEffect vs useEffect is that useLayoutEffect will be fired synchronously after DOM mutation and before the browser paint phase. (Reference)
However, I've came across some articles and they all seem to recommend to use useLayoutEffect for reading layout.
React docs:
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.
Kent C.Dodds:
useLayoutEffect: If you need to mutate the DOM and/or do need to perform measurements.
Ohans Emmanuel:
Where possible, choose the useEffect Hook for cases where you want to be unobtrusive in the dealings of the browser paint process. In the real world, this is usually most times! Well, except when you’re reading layout from the DOM or doing something DOM-related that needs to be painted ASAP.
As I understand, by the time the useEffect is fired, the browser has already passed the layout and paint phase, so reading layout in useEffect should be totally okay.
So my question: Is useLayoutEffect preferable to useEffect when reading layout and if yes, why? Taken that I just only read the layout and don't perform any additional state changes in the effect.

The following diagram always helps me to visualize the flow of hooks and also will let you clarify regarding why useLayoutEffect is recommended over useEffect for DOM based operations (where you're targetting stuff that you can update before current browser paint)
Link to the diagram - https://github.com/donavon/hook-flow

If you don't have DOM manipulating code in the hook and only reading layout useEffect will do just fine.
If you do have DOM manipulating code in the useEffect and see screen flickering move this code to useLayoutEffect.
It goes like this:
Render
useLayoutEffect (synchronously after all DOM mutations)
Paint
useEffect

The answer depends on what you as a developer consider 'preferable'. In the context of your question useLayoutEffect guarantees that you will see layout before mutation, useEffect shows you what happens after.

Related

Is ResizeObserver API necessary or preferred in React?

We can already detect dimension change by using ref and useEffect in React:
useEffect(() => {
console.log("height changed to", ref.current?.clientHeight)
}, [ref.current?.clientHeight])
I wonder what is the advantage of ResizeObserver over this ref + useEffect approach? I'm surprised there's no online discussion around this, given ResizeObserver has been there for awhile since 2018. I can see if you're using Vanilla Javascript then ResizeObserver might be the best way to get dynamic height.
But in React I just don't understand how ResizeObserver API is better. I tested both and in Chrome both fire updates almost at the same time. I researched online and many are talking about how to use React Hook with ResizeObserver, but rarely do these posts talk about ref + useEffect already suffice.
Does anyone know if using React, any advantage using ResizeObserver API, or it really doesn't differ much from ref + useEffect approach?
We can already detect dimension change by using ref and useEffect in React:
For a useEffect to run, the component must be rendering. For the component to be rendering, something somewhere must have set state. So if all of that is happening, then yes, your effect can notice the size has changed since the previous render.
But if nothing sets state, then none of that will happen. Maybe you're getting lucky, and some component happens to be setting state around the time the size changes, but that's not something you should rely on. If you delete some random component, or try to optimize performance by skipping rendering, you can suddenly break your resize "detection" code.
The point of the resize observer is to get notified that the change has happened. Then you can set state, and cause the rerender. So now instead of hoping a rerender happens, you know it will happen.

What does it mean by useState are asycnhronous in react

I found some old post that a guy having problem with his code in React and alot answer said that it was caused by because useState is asycnhronous. I was curious what it mean by asycnhronous and I found this article
useState is an asynchronous hook and it doesn't change the state
immediately, it has to wait for the component to re-render. useRef is
a synchronous hook that updates the state immediately and persists its
value through the component's lifecycle, but it doesn't trigger a
re-render
But i still don't understand what it means and why is such a problem. Can someone give me an example?
I would say this is one of the myth to call useState asynchronous.
IMHO, if you open the source code of react, I'm speaking to react 16.x and below (because i didn't read after 16), useState isn't asynchronous.
So why are we saying useState behaves as asynchronous code? We need some coding example.
const App = () => {
const [value, setValue] = useState(1)
const onClick = () => {
setValue(2)
console.log(value)
}
return <input value={value} />
}
In the above typical setup of useState, when you call setValue(2), value wouldn't become 2 right away. This is apparent if you put a console.log after that. Then why the input does show 2 instead of 1, you might ask?
That's because React made a second render to App, you can think of App has been called one more time after setValue. For this reason, people call useState async.
But then why I'm not calling useState async? well, this is a bit long story. The short story is that useState is implemented inside React using plain non-async codes, therefore you can't say a code async just because it has been called twice or it has been deferred to call. Async means a bit differently in Javascript. This is another topic which I won't get into here.
I don't want to speak for the React team as to why state changes are asynchronous, but here's some random dude's explanation. I'll be referring to the JavaScript event loop, which is basically a program that runs many times per second. Each time it runs, it processes a series of tasks synchronously. Asynchronous code is executed across several event loops. This is a very basic and oversimplified explanation - you should go read more about the event loop.
So your initial state declaration happens in your initial render - the first time the function is called. This initial render happens synchronously - meaning the function is executed top to bottom in a single event loop. It's worth pointing out that React components cannot be async:
const SomeComponent = () => {
const [foo, setFoo] = useState("bar");
return <div>The value of foo is "{bar}"</div>;
}
After your initial render, the state only changes when something happens: user clicks a button, the screen resizes, a timer interval fires, etc. Whenever an "event" happens, there can be a lot of processing going on in the JavaScript event loop.
Let's look at a button click, the event propagates all the way down and back up the entire DOM tree which contains the button. The browser is also rendering different states of the button, causing the browser to repaint. You also have developer code which is running in the button click handler which might be doing some heavy lifting like iterating over an array. This all happens within a single event loop. The point of this explanation is to convey that "a lot is going on". Eventually, the state will get updated with setFoo(...).
At this point, React now has to figure out which component changed, calculate and rerender your application in a virtual DOM, perform a diff with the actual DOM, and then apply any changes to the actual DOM. Only at this point does the browser finally paint the result to the screen. This whole operation can be very taxing on a CPU.
If react were to handle state changes synchronously, all of this virtual DOM diffing and calculating would happen in the same event loop as the initial button click. It is very likely that most apps would cause the browser to sporadically freeze and jitter because the CPU is doing so much work at one time.
There are also some other things to consider. Suppose the window resizes and a bunch of different components perform some calculations and update their state. You don't want react to synchronously rerender every time a component changes its state. You want react to kind of wait and collect a whole bunch of state changes and process them at the same time. Browsers also provide mechanisms like requestAnimationFrame to help web-based applications asynchronously render in such a way that works best for the user and their system/browser resources.
There are many other things to consider, but this post is getting long. Hope this helps.

useEffect or useMemo for API functions?

which is the best hook for dispatching API calls in a component. Usually I use useMemo for calling the API on the first render, and useEffect if I need extra side effects, is this correct? Becouse sometimes I get the following error:
'''index.js:1 Warning: Cannot update a component (Inscriptions) while rendering a different component (PaySummary). To locate the bad setState() call inside PaySummary, follow the stack trace as described in ...''''
That happens when I route to a component and rapidly change to another one, it doesn't "affect" the general behaivour becouse if i go back to the previous component it renders as expected correctly. So how should I do it?
Calling an API is a side effect and you should be using useEffect, not useMemo
Per the React docs for useEffect:
Data fetching, setting up a subscription, and manually changing the DOM in React components are all examples of side effects. Whether or not you’re used to calling these operations “side effects” (or just “effects”), you’ve likely performed them in your components before.
Per the React docs for useMemo:
Remember that the function passed to useMemo runs during rendering. Don’t do anything there that you wouldn’t normally do while rendering. For example, side effects belong in useEffect, not useMemo.
Performing those side effects (and modifying state) during rendering or with useMemo is the reason you encounter the errors you mention.
basically I rather to use useEffect in componentDidMount manner, with no dependency like below
useEffect(() => {
// Api call , or redux async action here...
}, [])
for calling api's at component mount state.
most of the time i find my self using useMemo for memoising the data at functional Component render level, for preventing the variable re-creation and persist the created data between renders except the dependency changes.
but for the context of your question, there is a hook called useLayoutEffect which is primarily used for actions to happen before painting the DOM, but as i said basically most of the time in projects i find calling apis in a simple useEffect with no dependencies aka, the did mount of your component, in order to load the required data for component!
A bit late but, while everything mentioned above is completely true; the error
'''index.js:1 Warning: Cannot update a component (Inscriptions) while rendering a different component (PaySummary). To locate the bad setState() call inside PaySummary, follow the stack trace as described in ...''''
Has to do with the fact that the API call is Asynchronous and when you rapidly change the pages, the set state call (for updating the data returned from the API call I assume) is still waiting to be called after the data is returned from the API. So, you have to always clean up your Async functions in useEffect to avoid this error.

What is the use case of useMemo in React?

I need help to understand when to use useMemo hook in React vs useState + useEffect. From what I've understood after reading other questions on S.O. and websites :
With useState you can create a value (changeable through the setter) and you can use useEffect to do whatever you need if some of the dependencies listed in the dependency array changes. On first render for example your component will be rendered with the initial value passed to useState, then the effect will run and your component will re-render with the new value you set with the setter in your effect.
With useMemo you can create a value that will be computed from a function you give to the hook and it will change if some of the dependencies in the dependency array changes. So far, to me, it looks like useState + useEffect except you don't have the setter to change the value. On render your useMemo will run if one of the dependencies has changed. Difference here : your component will wait for the value to be computed before rendering (not sure about this part).
From what I've read, useMemo should be used for heavy operations. But if it's blocks the rendering of the component what's the point ?
Some says that with the dependency array you can avoid unnecessary updates but I can also do it with useEffect without blocking the render ? If I don't have a heavy component to render, isn't it faster to use useEffect ?
Thank you :)
Edit :
I accepted Philip Feldmann's answer as it fits my needs. As suggested in the comments you can take a look at this question for a global comparison :)
You are correct, useEffect runs after rendering as a side effect. That means that when you don't want to block the render loop, you can use your version.
That version will however trigger another rerender through calling the setter.
The initial time to paint might be faster, but you'll instantly block the render loop again by setting the new value, which in most cases should be slower than just using useMemo directly.

Dispatch redux action before render with react hooks

So, as the title says: how can we dispatch a redux action before rendering a component?
I have a specific case where i need some shared state chunk cleared before component renders (in that case showing “loading...”) which is done through dispatching redux action.
Now, if i dispatch it with useEffect i get flickering of first stale/old data shown and then showing “loading...”.
So far i see 2 ways to solve it:
useLayoutEffect - i like it but not sure if its a good practice
redefine redux model - that one i would like to avoid plus it sounds a bit wierd
I might create custom Fetcher hook but doesnt that bring it back into realm of hocs/wrapper hells?
I just want to do something before first render.
The difference between useEffect and useLayoutEffect is that the latter is executed synchronously after initial render:
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.
If flickering is the only problem with useEffect and it disappears with useLayoutEffect then the latter should be used.

Resources