Problem:
I have an intent to write a parent components with an array of children components. It is a kind of classic TODO list. When I type something on child component’s textfield, it triggers the change on parent component, and parent re-renders itself and all the children.
There are going to be 1000+ of children components in parent, and I don’t want to re-render everything when I type something in one of the children’s textfields.
As an optimization technique I decided to use React.memo
on children, so if props of children do not change, they don’t re-render. But right now the state of a parent started to be randomly altered. I’ve spent a good amount of time on this one, but I still struggle to find the culprit.
You can play around with my code in here:
https://codesandbox.io/s/mutable-pine-m6twyv?file=/src/Parent.jsx
Click multiple times on “Add text” button. Then start typing on first textfield, and you will see something strange happening to the list: some items disappear, other’s values get rewritten
Solution:
Your useCallback
is missing the [texts]
dependency, so all bets are basically off.
Use the functional form of set...
to avoid having the dependencies in the first place:
const addText = React.useCallback(() => {
setTexts(texts => [...texts, "new bla"]);
}, []);
const change = React.useCallback((newText, index) => {
setTexts(texts => {
const newTexts = [...texts];
newTexts[index] = newText;
return newTexts;
});
}, []);
(Also, avoid React.memo
unless you really do know you need it…)