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.
Related
I always thought of a side-effect as a read or write operation that is performed while rendering a functional component, and that accesses resources outside of those provided as props. Sort of like the definition of a pure function.
So when I needed to read window.location, I figured it had to be in a useEffect. Turns out the linter doesn't require that window.location be a dependency, so I guess it's ok to access window directly. This means my mental model of a React side-effect is wrong... But why?
If merely fetching data (which is a read operation) is considered a side-effect, then why isn't window.location?
So now I'm wondering, are functional components actually not really pure? Are they only "write pure" but not "read pure"?
How the useEffect or any other memoizing hooks(useCallback, useMemo,...) work works is:
Component re-renders
The dependency list is looked through to detect changes in any of them
If a change is detected, the function inside the useEffect is called
The issue with window.location or any other outer scope variables is that they do not initiate a component re-render to begin with.
This is the exact message on ESLint
Outer scope values like 'window.location.href' aren't valid
dependencies because mutating them doesn't re-render the component
And to answer your question, yes and no.
According this article :
A React component is considered pure if it renders the same output for
the same state and props
So if you add a dependency to an outer scope variable like window in your component, you can't call that component pure anymore.
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.
In my react js application i have a reduce function that is responsible to loop trough an array of 4 strings and to return a string with all these items. Is there a reason to wrap the function with useMemo hook or it is redundant in this situation?
useMemo caches the result of the given function so It's not recalculated on every re-render.
Whether to memoize depends on how often the function's dependencies change. Still it's unlikely that you need to recalculate the value on every render, so generally its a good idea to wrap it with useMemo
I'm creating a simple React application where a parent component renders a number of children components based on an input range slider (using array.map).
I'm performing certain actions within a useEffect with a dependency array in the child component (particularly, I'm obtaining a 3D model's bounding box size using react-three-fiber). Even though I have the dependency array, I can see from the console logs that the useEffect executes each time I move the slider.
How can I ensure that this useEffect only executes once? I was considering passing the useRef of the model to the parent and doing the useEffect actions there, but I'm curious if there's a way to modify useEffect such that it just executes once.
After a deep understanding of my needs, one of the arguments was changing.
Functions not through a useCallback will always change. Rebuilt objects (and to some extent, arrays) are new as well (unless memoized).
I checked what is changing first. Instead of using useRef, figure out what is changing in the data.
But in reality, if that dependency was actually needed, I can memoize it (e.g. useMemo) instead of just removing it.
Now I'm on changing class based component into functional component, and there's instances which I should determine to use useRef or useState.
I already tried to get my answers using stackoverflow Q&As, it keeps me wondering.
What I understood is useRef and useState keeps value during whole apps, and useState cause rerendering and useRef is not.
we needs rerendering process if there's some changes in view, If so, Should we create whole variables with useRef which is not in return( <> ...</>)> ?
Generally Ref is used when you dont want to component re-render again but you want value in some form so that you can use later. In layman term if you just want to play with dom related stuff like updating width, height etc.
Common example for using ref:
When you want to focus in and out your input without using state(as you dont want to render the component again)
Updating dynamically style(Fox ex: You create your accordian then you want to update heigh and show transition when according open and close(if you dont want to show you can avoid this example))
If you want to create this type of utilities then you dont need to play with states you can do only with ref
for most use cases you want to handle your react component's behavior through state provided from useState (or props where you get as parameter). that's the React way to go.
eventually there will be cases to useRef, where you may need for example to access a DOM element directly for some special reason. but they are exception cases. if you you see yourself calling useRef throughout your application you are most likely doing something wrong.