I want to manage a number of child components in parent component.
However, when one of child component trigger onCheck event, all child components were re-rendered. (because handleToggleCheck function was changed.)
const Parent = (props) => {
const {codes} = props // codes is list length 1000
const [checkedCodes, setCheckedCodes] = useState<Set<string>>(new Set())
const handleToggleCheck = (code) => {
if (!checkedCodes.has(code)) checkedCodes.add(code)
else checkedCodes.delete(code)
setCheckedCodes(new Set(checkedCodes))
}
return (
codes.map(code => (
<Child key={code} checked={checkedCodes.has(code)} onCheck={handleToggleCheck} code={code} />
))
}
}
const Child = (props) => {
const {checked, code, onCheck} = props
return (
<input type=“checkbox” checked={checked} onChange={() => onCheck(code)} />
)
}
I tried to wrap handleToggleCheck function using useCallback, but It doesn’t work because checkedCodes re-maked when called handleToggleCheck.
const handleToggleCheck = useCallback((code) => {
//…
}, [checkedCodes])
And I tried also use useRef instead of useState, but it doesn’t re-render child component when checkedCodes changed.
//…
const checkedCodes = useRef(new Set())
//…
return (
codes.map(code => (
<Child … checked={checkedCodes.current.has(code)} … />
))
)
What is the best way?
>Solution :
I tried to wrap handleToggleCheck function using useCallback, but It doesn’t work because checkedCodes re-maked when called handleToggleCheck.
const handleToggleCheck = useCallback((code) => { //… }, [checkedCodes])
You can remove checkedCodes as a dependency with a little rewriting:
const handleToggleCheck = useCallback((code) => {
setCheckedCodes(prev => {
if (!prev.has(code)) prev.add(code);
else prev.delete(code);
return new Set(prev);
});
}, [])
However, useCallback alone will not prevent the children from being rendered. You will also need to use React.memo to tell react it should skip the component if none of its props have changed:
import { memo } from 'react';
const Child = memo((props) => {
const {checked, code, onCheck} = props
return (
<input type=“checkbox” checked={checked} onChange={() => onCheck(code)} />
)
})