How To Avoid Rerender All Child Components Which In Loop When Parent Component State Update
Solution 1:
for that you can use React.memo that will memoize your component if props remains the same. But given your code you need to make some extra changes:
you have to apply
useCallback
to memoize onChangeHandle function;to memoize properly onChangeHandle you need to refactor it. you can't pass
selectedChild
directly, otherwise it memoizes its value. usesetSelectedChild
passing as argument a function that takesselectedChild
instead.your Child should receive
isSelected
as boolean value instead of function. otherwise props will remain the same and Child never updates;import React, { useState, memo, useCallback } from "react"; function Parent() { const [selectedChild, setSelectedChild] = useState([]); const onChangeHandle = useCallback((event, id) => { setSelectedChild(selectedChild => { const checked = event.target.checked; let updatedArray = [...selectedChild]; if (checked) { if (!selectedChild.includes(id)) { updatedArray.push(id); } } else { var index = updatedArray.indexOf(id); if (index !== -1) { updatedArray.splice(index, 1); } } return updatedArray; }); }, []); const dummy = id => { return selectedChild.includes(id); }; const renderChildren = () => [1, 2, 3].map((value, index) => { return ( <Child key={index} index={index} value={value} handle={onChangeHandle} isSelected={dummy(index)} /> ); }); return ( <div> <table> <tbody>{renderChildren()}</tbody> </table> <div>{selectedChild}</div> </div> ); } const Child = memo(({ index, value, handle, isSelected }) => { console.log("rendering"); return ( <tr> <td> <input type="checkbox" checked={isSelected} onChange={event => handle(event, index)} /> </td> <td> hello {index} {value} </td> </tr> ); }); export default function App() { return ( <div className="App"> <Parent /> </div> ); }
https://stackblitz.com/edit/so-memo-children?file=src/App.js
Solution 2:
The basic answer is use React.memo
on Child
.
const Child = memo(function Child(...) {...})
But to make memo
work, the component needs to receive the same props if it shouldn't get rerendered. That means using useCallback
on onChangeHandle
:
const onChangeHandle = useCallback((event, id) => {...}, [])
But since onChangeHandle
uses selectedChild
that always changes on checkbox change, you'll also need to ref it using useRef
:
const selectedChildRef = useRef();
selectedChildRef.current = selectedChild;
and use reffed version inside of onChangeHandle
.
The last thing that needs to be done is to change isSelected
prop from function to just a flag since it needs to be run on each checkbox change:
isSelected={selectedChild.includes(index)}
Solution 3:
You could implement shouldComponentUpdate (doc: https://reactjs.org/docs/react-component.html#shouldcomponentupdate) inside the definition of Child to have more control over when it rerenders. But that's only meant for cases where you have performance issues- generally you don't have to worry about it, and letting them all rerender is standard.
Post a Comment for "How To Avoid Rerender All Child Components Which In Loop When Parent Component State Update"