Is this incorrect use of useCallback and useMemo? - reactjs

When should we worry about functional components redefining variables and functions??
I think this first case is clearly unnecessary, functions is not expensive to create(and the react dev tools profile test didn't detect performace change with useCallback)
import React, { useState, useMemo, useCallback } from "react";
export const App = () => {
const [counter, setCounter] = useState(1);
const showCounter = useCallback(() => {
console.log(counter);
}, [counter]);
return (
<>
<button onClick={showCounter}>Show</button>
<button onClick={() => setCounter(counter + 1)}>Add</button>
</>
);
};
In the other hand, in this other exemple, with react dev tools we can detect that useMemo cuts in half the time of rendering:
import React, { useState, useMemo, useCallback } from "react";
export const App = () => {
const [counter, setCounter] = useState(1);
const [list, setList] = useState<number[]>([]);
function setListItem(item: number) {
setList([...list, item]);
}
//should we useMemo here?
const domList = useMemo(
() =>
list.map((value: number, index: number) => (
<li key={index}> {value} </li>
)),
[list]
);
return (
<>
<p>{counter}</p>
<button onClick={() => setCounter(counter - 1)}>Subtract</button>
<button onClick={() => setCounter(counter + 1)}>Add</button>
<button onClick={() => setListItem(counter)}>Push to array</button>
<h1>List</h1>
<ul>{domList}</ul>
</>
);
};
But still less than a millisecond of gain and array maps and JSX array are not something really expensive when we talk about front-end either. However, leaving an array map method run in each render is very uncomfortable to see. So, what of those things should we do? (Let's forget about when we have useEffect that depends of some variables that make the useMemo necessary)
useCallback and useMemo in all functions and variables that don't need to be redefined in each render.
useCallback and useMemo only in things that we can clearly see a performance gain(even if most time would not count as an improvement to UX). So we would need useMemo in this second example.
useCallback and useMemo only when not using it in a specific case we would get a great UX decline. So only really expensive functions would useCallback

The performance you gain with each of them is different. Yes, for useMemo if the calculation you are memoizing is expensive, it offers a clear immediate benefit. However, for useCallback and useMemo, the long-term benefits refer to avoiding unnecessary renders in child components, not the recalculation cost.
Remember, if any of the props in a component change, they may trigger a render call, and the higher in the component tree this is the case, the more it will affect performance. That is the reason we normally use those hooks.
In general, components have several state elements, and with memo hooks, we can establish dependencies to avoid computational redundancy. For instance, in your synthetic case, you have two state elements: counter, and list. Each time counter changes, you prevented domList to be recalculated by making it dependent only on list. If this was a leaf node, sure no performance gain, however, this is the root of your component tree, and without those hooks, performance will not scale as you add more state elements and you will have to refactor your code to address performance. Sure, <ul>{domList}</ul> can be costly if the list has more than 1000 elements, but <ul><ExpensiveCutie domList={domList} /></ul> can take you weeks to notice, debug, and refactor.
In short, I recommend using memo hooks in container components and not in leaf components. Yet, what if your leaf component becomes a container as you are implementing it?
Before you go, do you even need to use memo()? Read more here.

Related

Prevent re-rendering when child components list expands

In the following example, every click of the button should only render the next Number component, but instead it re-renders the whole list again. I would like to know the best practice to prevent the previous one from re-rendering. Thank you.
const Number = (props) =>{return (<div> {props.number} </div>)}
const NumberListUpTo = () =>{
const [listLength, setListLength] = useState(1);
return(
<>
<button onClick = {() => setListLength(listLength + 1)}>add one more</button>
{
Array.from({length: listLength}, (v, i) => i).map(
(i) => (<Number number = {i} />))
}
</>)
}
Use React.memo to memoize your components.
You should always provide a key for React components when you are rendering an array of elements.
Edit:
As React documentation says:
This method only exists as a performance optimization. Do not rely on it to “prevent” a render, as this can lead to bugs.
Do not try to prevent renders or memoize every component. Try to optimize your code whenever you there is a performance issue. Optimization in React, using memo, useMemo, useCallback, etc) comes at a price; they take resources and may even slow down your app.

UseCallback still triggering infinitely, What should I do? [duplicate]

As said in docs, useCallback
Returns a memoized callback.
Pass an inline callback and an array of inputs. useCallback will return a memoized version of the callback that only changes if one of the inputs has changed. This is useful when passing callbacks to optimized child components that rely on reference equality to prevent unnecessary renders (e.g. shouldComponentUpdate).
const memoizedCallback = useCallback(
() => {
doSomething(a, b);
},
[a, b],
);
But how does it work and where is the best to use it in React?
P.S. I think visualisation with codepen example will help everyone to understand it better. Explained in docs.
This is best used when you want to prevent unnecessary re-renders for better performance.
Compare these two ways of passing callbacks to child components taken from React Docs:
1. Arrow Function in Render
class Foo extends Component {
handleClick() {
console.log('Click happened');
}
render() {
return <Button onClick={() => this.handleClick()}>Click Me</Button>;
}
}
2. Bind in Constructor (ES2015)
class Foo extends Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
console.log('Click happened');
}
render() {
return <Button onClick={this.handleClick}>Click Me</Button>;
}
}
Assuming <Button> is implemented as a PureComponent, the first way will cause <Button> to re-render every time <Foo> re-renders because a new function is created in every render() call. In the second way, the handleClick method is only created once in <Foo>'s constructor and reused across renders.
If we translate both approaches to functional components using hooks, these are the equivalents (sort of):
1. Arrow Function in Render -> Un-memoized callback
function Foo() {
const handleClick = () => {
console.log('Click happened');
}
return <Button onClick={handleClick}>Click Me</Button>;
}
2. Bind in Constructor (ES2015) -> Memoized callbacks
function Foo() {
const memoizedHandleClick = useCallback(
() => console.log('Click happened'), [],
); // Tells React to memoize regardless of arguments.
return <Button onClick={memoizedHandleClick}>Click Me</Button>;
}
The first way creates callbacks on every call of the functional component but in the second way, React memoizes the callback function for you and the callback is not created multiple times.
Hence in the first case if Button is implemented using React.memo it will always re render (unless you have some custom comparison function) because the onClick prop is different each time, in the second case, it won't.
In most cases, it's fine to do the first way. As the React docs state:
Is it OK to use arrow functions in render methods? Generally speaking,
yes, it is OK, and it is often the easiest way to pass parameters to
callback functions.
If you do have performance issues, by all means, optimize!
useCallback and useMemo are an attempt to bypass weak spots that come with the functional programming approach chosen with React hooks. In Javascript, each entity, no matter if it is a function, variable, or whatever, is created into the memory when the execution will enter the function's code block. This is a big issue for a React that will try to detect if the component needs to be rendered. The need for rerendering is deducted based on input props and contexts. Let's see a simple example without useCallback.
const Component = () => {
const [counter, setCounter] = useState(0);
const handleClick = () => {
setCounter(counter + 1);
}
return <div>
Counter:{counter}<br/>
<button onClick={handleClick}>+1</button>
</div>
}
Note that the handleClick -function instance will be created on each function call inside the block, so the event handler's address on each call will be different. The React framework will always see the event handler as changed because of this. In the example above, React will think handleClick as a new value on each call. It simply has no tools to identify it as the same call.
What useCallback does, it internally stores the first introduced version of the function and returns it to the caller, if the listed variables have not changed.
const Component = () => {
const [counter, setCounter] = useState(0);
const handleClick = useCallback(() => {
setCounter(counter + 1);
}, [])
return <div>
Counter:{counter}<br/>
<button onClick={handleClick}>+1</button>
</div>
}
Now, with the code above, React will identify the handleClick -event handler as the same, thanks to useCallback -function call. It will always return the same instance of function and React component rendering mechanism will be happy.
Storing the function internally by the useCallback will end up with a new problem. The stored instance of the function call will not have direct access to the variables of the current function call. Instead, it will see variables introduced in the initial closure call where the stored function was created. So the call will not work for updated variables. Thats why you need need tell if some used variables have changed. So that the useCallback will store the current function call instance as a new stored instance. The list of variables as the second argument of the useCallback is listing variables for this functionality. In our example, we need to tell to useCallback -function that we need to have a fresh version of counter -variable on each call. If we will not do that, the counter value after the call will be always 1, which comes from the original value 0 plus 1.
const Component = () => {
const [counter, setCounter] = useState(0);
const handleClick = useCallback(() => {
setCounter(counter + 1);
}, [counter])
return <div>
Counter:{counter}<br/>
<button onClick={handleClick}>+1</button>
</div>
}
Now we have a working version of the code that will not rerender on every call.
It is good to notice that the useState -call is here just for the same reason. Function block does not have an internal state, so hooks are using useState, useCallback and useMemo to mimic the basic functionality of classes. In this sense, functional programming is a big step back in history closer to procedural programming.
useMemo is the same kind of mechanism as useCallback but for other objects and variables. With it, you can limit the need for component rerender, as the useMemo -function will return the same values on each function call if the listed fields have not changed.
This part of the new React hooks -approach is definitely the weakest spot of the system. useCallback is pretty much counterintuitive and really error-prone. With useCallback-calls and dependencies, it is too easy to end up chasing internal loops. This caveat we did not have with the React Class approach.
The original approach with classes was more efficient after all. The useCallback will reduce the need to rerender, but it regenerates the function again every time when some of its dependant variables will change, and matching if the variables have changes itself will make overhead. This may cause more rerenders than necessary. This is not the case with React classes.
I've made a small example to help others understand better how it behaves. You can run the demo here or read the code bellow:
import React, { useState, useCallback, useMemo } from 'react';
import { render } from 'react-dom';
const App = () => {
const [state, changeState] = useState({});
const memoizedValue = useMemo(() => Math.random(), []);
const memoizedCallback = useCallback(() => console.log(memoizedValue), []);
const unMemoizedCallback = () => console.log(memoizedValue);
const {prevMemoizedCallback, prevUnMemoizedCallback} = state;
return (
<>
<p>Memoized value: {memoizedValue}</p>
<p>New update {Math.random()}</p>
<p>is prevMemoizedCallback === to memoizedCallback: { String(prevMemoizedCallback === memoizedCallback)}</p>
<p>is prevUnMemoizedCallback === to unMemoizedCallback: { String(prevUnMemoizedCallback === unMemoizedCallback) }</p>
<p><button onClick={memoizedCallback}>memoizedCallback</button></p>
<p><button onClick={unMemoizedCallback}>unMemoizedCallback</button></p>
<p><button onClick={() => changeState({ prevMemoizedCallback: memoizedCallback, prevUnMemoizedCallback: unMemoizedCallback })}>update State</button></p>
</>
);
};
render(<App />, document.getElementById('root'));
An event handler gets recreated and assigned a different address on every render by default, resulting in a changed ‘props’ object. Below, button 2 is not repeatedly rendered as the ‘props’ object has not changed. Notice how the entire Example() function runs till completion on every render.
const MyButton = React.memo(props=>{
console.log('firing from '+props.id);
return (<button onClick={props.eh}>{props.id}</button>);
});
function Example(){
const [a,setA] = React.useState(0);
const unmemoizedCallback = () => {};
const memoizedCallback = React.useCallback(()=>{},[]); // don’t forget []!
setTimeout(()=>{setA(a=>(a+1));},3000);
return (<React.Fragment>
<MyButton id="1" eh={unmemoizedCallback}/>
<MyButton id="2" eh={memoizedCallback}/>
<MyButton id="3" eh={()=>memoizedCallback}/>
</React.Fragment>);
}
ReactDOM.render(<Example/>,document.querySelector("div"));

Difference between useEffect and useMemo

I'm trying to wrap my head around what exactly the useMemo() React hook is.
Suppose I have this useMemo:
const Foo = () => {
const message = useMemo(() => {
return readMessageFromDisk()
}, [])
return <p>{message}</p>
}
Isn't that exactly the same as using a useState() and useEffect() hook?
const MyComponent = () => {
const [message, setMessage] = useState('')
useEffect(() => {
setMessage(readMessageFromDisk())
}, [])
return <p>{message}</p>
}
In both cases the useMemo and useEffect will only call if a dependency changes.
And if both snippes are the same: what is the benefit of useMemo?
Is it purely a shorthand notation for the above useEffect snippet. Or is there some other benefit of using useMemo?
useEffect is used to run the block of code if the dependencies change. In general you will use this to run specific code on the component mounting and/or every time you're monitoring a specific prop or state change.
useMemo is used to calculate and return a value if the dependencies change. You will want to use this to memoize a complex calculation, e.g. filtering an array. This way you can choose to only calculate the filtered array every time the array changes (by putting it in the dependency array) instead of every render.
useMemo does the same thing as your useEffect example above except it has some additional performance benefits in the way it runs under the hood.

is useCallback a performance boost for the react app?

could someone explain to me if the use of useMemo and useCallback is expensive or cheap? I've checked the React's source code and I think they are cheap to use, but I've also read some people saying they are not.
In a Next.js context using useCallback:
const MyComp = () => {
const router = useRouter():
const handleClick = useCallback(() => router.push('/some-path'), [router]);
return <button onClick={handleClick} />
}
vs plain arrow function here:
const MyComp = () => {
const router = useRouter():
return <button onClick={() => router.push('/some-path')} />
}
Am I saving re-renders with useCallback?
The cost of memoize and comprare the dependencies array [router], is more expensive?
Additional info: Checking the React's code I saw that they compare the deps array items using Object.is instead of === or ==.
Someone knows why?
Also checking this component render:
import {useCallback, useState} from "react";
let i = 0
const CallbackDemo = () => {
const [value, setValue] = useState('');
console.log('render', i++);
const handleClick = useCallback(() => setValue(Math.random()), []);
return (
<div>
<span>{value}</span>
<button onClick={handleClick}>New set</button>
</div>
);
}
export default CallbackDemo;
I saw the same count of renders using or not using useCallback
Am I saving re-renders with useCallback?
Not in that specific case, no. The useCallback code does let you save roughly the cost of an assignment statement because it doesn't have to update the click handler on the button element, but at the cost of a function call and going through the array of dependencies looking for differences. So in that specific case, it's probably not worth doing.
If you had a more complex child component, and that component was optimized not to re-render when called with the same props (for instance, via React.memo or React.PureComponent or similar), or you were passing the function to a bunch of child components, then you might get some performance improvements by not making them re-render.
Consider this example, where simpleClickHandler is always recreated but memoizedClickHandler is reused¹ via useCallback:
const { useState, useCallback } = React;
const Parent = () => {
const [counter, setCounter] = useState(0);
console.log("Parent called");
const simpleClickHandler = () => {
console.log("Click occurred");
setCounter(c => c + 1);
};
const memoizedClickHandler = useCallback(() => {
console.log("Click occurred");
setCounter(c => c + 1);
}, []);
return (
<div>
Count: {counter}
<Child onClick={simpleClickHandler} handlerName="simpleClickHandler">simpleClickHandler</Child>
<Child onClick={memoizedClickHandler} handlerName="memoizedClickHandler">memoizedClickHandler</Child>
</div>
);
};
const Child = React.memo(({handlerName, onClick, children}) => {
console.log(`Child using ${handlerName} called`);
return (
<div onClick={onClick}>{children}</div>
);
});
ReactDOM.render(<Parent/>, document.getElementById("root"));
<div id="root"><?div>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.2/umd/react-dom.production.min.js"></script>
Note that when you click, only the child being passed simpleClickHandler re-renders, not the one being passed memoizedClickHandler, because memoizedClickHandler's value is stable but simpleClickHandler's value changes every time.
Using useCallback requires more work in the parent (checking to see if the previous function can be reused), but may help save work in child components.
It's important to note that the stability useCallback (and useMemo) give you are only appropriate for performance reasons, not correctness. React can throw away the previous copy of a handler and new a new one if it wants to, even if the deps haven't changed. If you need a correctness guarantee (the result definitely 100% will not change unless the deps change), you have use a ref. But that's a very rare use case.
Additional info: Checking the React's code I saw that they compare the deps array items using Object.is instead of === or ==.
Someone knows why?
Primarily because NaN === NaN is false, because all comparisons with NaN are false. So if they used ===, any deps array containing NaN would always be considered different from the previous one. But using Object.is avoids that problem, because Object.is(NaN, NaN) is true.
¹ Note that "reused" here means: a new handler is created every time, just like simpleClickHandler, but useCallback may return the previous handler you've given it if the deps haven't changed, so the new one is thrown away. (JavaScript engines are really quick at allocating and reclaiming short-lived objects.)
useCallback like useMemo indeed improve performance
but!!! you don't need to use it to everything because it will make your website slower.
this is better for the heavy lifting components like for charts and stuff like that.
that consume a lot of resource and take a lot of time to process and this will make this specific component load much more faster and not stuck everytime you do a change.
you can see deep compression like this:
react useEffect comparing objects
this link will show you for instance how to do a deep compression for use effect

Question regarding benefit of React useCallback hook [duplicate]

As said in docs, useCallback
Returns a memoized callback.
Pass an inline callback and an array of inputs. useCallback will return a memoized version of the callback that only changes if one of the inputs has changed. This is useful when passing callbacks to optimized child components that rely on reference equality to prevent unnecessary renders (e.g. shouldComponentUpdate).
const memoizedCallback = useCallback(
() => {
doSomething(a, b);
},
[a, b],
);
But how does it work and where is the best to use it in React?
P.S. I think visualisation with codepen example will help everyone to understand it better. Explained in docs.
This is best used when you want to prevent unnecessary re-renders for better performance.
Compare these two ways of passing callbacks to child components taken from React Docs:
1. Arrow Function in Render
class Foo extends Component {
handleClick() {
console.log('Click happened');
}
render() {
return <Button onClick={() => this.handleClick()}>Click Me</Button>;
}
}
2. Bind in Constructor (ES2015)
class Foo extends Component {
constructor(props) {
super(props);
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
console.log('Click happened');
}
render() {
return <Button onClick={this.handleClick}>Click Me</Button>;
}
}
Assuming <Button> is implemented as a PureComponent, the first way will cause <Button> to re-render every time <Foo> re-renders because a new function is created in every render() call. In the second way, the handleClick method is only created once in <Foo>'s constructor and reused across renders.
If we translate both approaches to functional components using hooks, these are the equivalents (sort of):
1. Arrow Function in Render -> Un-memoized callback
function Foo() {
const handleClick = () => {
console.log('Click happened');
}
return <Button onClick={handleClick}>Click Me</Button>;
}
2. Bind in Constructor (ES2015) -> Memoized callbacks
function Foo() {
const memoizedHandleClick = useCallback(
() => console.log('Click happened'), [],
); // Tells React to memoize regardless of arguments.
return <Button onClick={memoizedHandleClick}>Click Me</Button>;
}
The first way creates callbacks on every call of the functional component but in the second way, React memoizes the callback function for you and the callback is not created multiple times.
Hence in the first case if Button is implemented using React.memo it will always re render (unless you have some custom comparison function) because the onClick prop is different each time, in the second case, it won't.
In most cases, it's fine to do the first way. As the React docs state:
Is it OK to use arrow functions in render methods? Generally speaking,
yes, it is OK, and it is often the easiest way to pass parameters to
callback functions.
If you do have performance issues, by all means, optimize!
useCallback and useMemo are an attempt to bypass weak spots that come with the functional programming approach chosen with React hooks. In Javascript, each entity, no matter if it is a function, variable, or whatever, is created into the memory when the execution will enter the function's code block. This is a big issue for a React that will try to detect if the component needs to be rendered. The need for rerendering is deducted based on input props and contexts. Let's see a simple example without useCallback.
const Component = () => {
const [counter, setCounter] = useState(0);
const handleClick = () => {
setCounter(counter + 1);
}
return <div>
Counter:{counter}<br/>
<button onClick={handleClick}>+1</button>
</div>
}
Note that the handleClick -function instance will be created on each function call inside the block, so the event handler's address on each call will be different. The React framework will always see the event handler as changed because of this. In the example above, React will think handleClick as a new value on each call. It simply has no tools to identify it as the same call.
What useCallback does, it internally stores the first introduced version of the function and returns it to the caller, if the listed variables have not changed.
const Component = () => {
const [counter, setCounter] = useState(0);
const handleClick = useCallback(() => {
setCounter(counter + 1);
}, [])
return <div>
Counter:{counter}<br/>
<button onClick={handleClick}>+1</button>
</div>
}
Now, with the code above, React will identify the handleClick -event handler as the same, thanks to useCallback -function call. It will always return the same instance of function and React component rendering mechanism will be happy.
Storing the function internally by the useCallback will end up with a new problem. The stored instance of the function call will not have direct access to the variables of the current function call. Instead, it will see variables introduced in the initial closure call where the stored function was created. So the call will not work for updated variables. Thats why you need need tell if some used variables have changed. So that the useCallback will store the current function call instance as a new stored instance. The list of variables as the second argument of the useCallback is listing variables for this functionality. In our example, we need to tell to useCallback -function that we need to have a fresh version of counter -variable on each call. If we will not do that, the counter value after the call will be always 1, which comes from the original value 0 plus 1.
const Component = () => {
const [counter, setCounter] = useState(0);
const handleClick = useCallback(() => {
setCounter(counter + 1);
}, [counter])
return <div>
Counter:{counter}<br/>
<button onClick={handleClick}>+1</button>
</div>
}
Now we have a working version of the code that will not rerender on every call.
It is good to notice that the useState -call is here just for the same reason. Function block does not have an internal state, so hooks are using useState, useCallback and useMemo to mimic the basic functionality of classes. In this sense, functional programming is a big step back in history closer to procedural programming.
useMemo is the same kind of mechanism as useCallback but for other objects and variables. With it, you can limit the need for component rerender, as the useMemo -function will return the same values on each function call if the listed fields have not changed.
This part of the new React hooks -approach is definitely the weakest spot of the system. useCallback is pretty much counterintuitive and really error-prone. With useCallback-calls and dependencies, it is too easy to end up chasing internal loops. This caveat we did not have with the React Class approach.
The original approach with classes was more efficient after all. The useCallback will reduce the need to rerender, but it regenerates the function again every time when some of its dependant variables will change, and matching if the variables have changes itself will make overhead. This may cause more rerenders than necessary. This is not the case with React classes.
I've made a small example to help others understand better how it behaves. You can run the demo here or read the code bellow:
import React, { useState, useCallback, useMemo } from 'react';
import { render } from 'react-dom';
const App = () => {
const [state, changeState] = useState({});
const memoizedValue = useMemo(() => Math.random(), []);
const memoizedCallback = useCallback(() => console.log(memoizedValue), []);
const unMemoizedCallback = () => console.log(memoizedValue);
const {prevMemoizedCallback, prevUnMemoizedCallback} = state;
return (
<>
<p>Memoized value: {memoizedValue}</p>
<p>New update {Math.random()}</p>
<p>is prevMemoizedCallback === to memoizedCallback: { String(prevMemoizedCallback === memoizedCallback)}</p>
<p>is prevUnMemoizedCallback === to unMemoizedCallback: { String(prevUnMemoizedCallback === unMemoizedCallback) }</p>
<p><button onClick={memoizedCallback}>memoizedCallback</button></p>
<p><button onClick={unMemoizedCallback}>unMemoizedCallback</button></p>
<p><button onClick={() => changeState({ prevMemoizedCallback: memoizedCallback, prevUnMemoizedCallback: unMemoizedCallback })}>update State</button></p>
</>
);
};
render(<App />, document.getElementById('root'));
An event handler gets recreated and assigned a different address on every render by default, resulting in a changed ‘props’ object. Below, button 2 is not repeatedly rendered as the ‘props’ object has not changed. Notice how the entire Example() function runs till completion on every render.
const MyButton = React.memo(props=>{
console.log('firing from '+props.id);
return (<button onClick={props.eh}>{props.id}</button>);
});
function Example(){
const [a,setA] = React.useState(0);
const unmemoizedCallback = () => {};
const memoizedCallback = React.useCallback(()=>{},[]); // don’t forget []!
setTimeout(()=>{setA(a=>(a+1));},3000);
return (<React.Fragment>
<MyButton id="1" eh={unmemoizedCallback}/>
<MyButton id="2" eh={memoizedCallback}/>
<MyButton id="3" eh={()=>memoizedCallback}/>
</React.Fragment>);
}
ReactDOM.render(<Example/>,document.querySelector("div"));

Resources