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
2
Answers
The issue you’re encountering with the state updates and rendering behavior in your React components is related to the way you’re handling the child components and their keys. Specifically, when adding new text entries, React encounters the following problems:
When you add a new text entry and use the index as the
key
for each child component, it can lead to issues because the index is not a stable identifier. React might have difficulties determining which child components to update when the list changes.Using
index
as thekey
and updating the parent’s state can cause React to re-render the entire list, which is not efficient for a large number of child components.To optimize the rendering behavior and avoid the issues you described, you should provide stable and unique keys for each child component. In your case, you can use the text value itself as a key since it’s unique and stable within the context of your TODO list.
You can try this:
With this change, each child component is identified by the text content, and React can efficiently determine which components need to be re-rendered when changes occur. This should improve the performance and stability of your TODO list with a large number of child components.
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:(Also, avoid
React.memo
unless you really do know you need it…)