Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

React: How to prevent re-rendering child components in `map`?

I tried to boil down the problem into an example as simple as possible:

We have a list of child components, each called NumChoice, each representing a number. NumChoice is wrapped in React.memo. In the parent component, we have an array of booleans, choices, each corresponding to one of the child components NumChoice. At first, all the elements of choices are false. To render the child components, we iterate through choices, and for each choice, generate the corresponding child component NumChoice. We define a function chooseDivisibles in the parent component, using useCallback that is called from each child component NumChoice. chooseDivisibles takes the index of the NumChoice who called it and changes the corresponding element of choices to true. Each NumChoice has a "red" background color if its corresponding element in choices is true, otherwise, its background color is "white".

The complete code is available at: https://codesandbox.io/s/react-rerender-l4e3c?fontsize=14&hidenavigation=1&theme=dark

Wrapping NumChoice in React.memo and chooseDivisibles in useCallback, we expected to only rerender NumChoice components whose corresponding element of choices changes but React re-renders them all. chooseDivisibles is wrapped in useCallback, which lists no dependency other than setChoices. Also, NumChoice is wrapped in React.memo and it should only rerender if the specified props change, but they do not, and changing choices should not have any effect on rerendering NumChoice. If we exclude checking the equality of chooseDivisibles in previous and next props, it works as expected, but I argue that the comparison of previous and next chooseDivisibles should not affect rerendering NumChoice because it is wrapped in useCallbackand does not depend on choices. How can we prevent re-rendering the NumChoice components whose props are not changed?

like image 402
1man Avatar asked Nov 07 '22 09:11

1man


1 Answers

Ah I see that in NumChoice.js we're also asserting prevProps.chooseDivisibles === nextProps.chooseDivisibles, which is always false, since chooseDivisibles={event => chooseDivisibles(idx)} generates a new function every time

If you remove prevProps.chooseDivisibles === nextProps.chooseDivisibles, it will only re-render the affected ones!

like image 53
TiHuan Avatar answered Nov 15 '22 05:11

TiHuan