重新渲染键值对对象组件
Re-rendering on key-value pair object components
我想避免在 <ChildComponent/>
中使用 onClick 更新我的状态时重新渲染我的子组件 <ChildComponent/>
。
我在 <ParentComponent/>
中有我的回调函数,它更新键值对对象的值之一。
在父组件中
const _keyValueObject = useMemo(() => utilityFunction(array, object), [array, object])
const [keyValueObject, setKeyValueObject] = useState<SomeTransport>(_keyValueObject)
const handleStateChange = useCallback((id: number) => {
setKeyValueObject(keyValueObject => {
const temp = { ... keyValueObject }
keyValueObject[id].isChecked = ! keyValueObject[id].isChecked
return temp
})
}, [])
return(
<Container>
{!! keyValueObject &&
Object.values(keyValueObject).map(value => (
<ValueItem
key={value.id}
category={value}
handleStateChange ={handleStateChange}
/>
))}
</Container>
)
在子组件中 ValueItem
const clickHandler = useCallback(
event => {
event.preventDefault()
event.stopPropagation()
handleStateChange(value.id)
},
[handleStateChange, value.id],
)
return (
<Container>
<CheckBox checked={value.isChecked} onClick={clickHandler}>
{value.isChecked && <Icon as={CheckboxCheckedIcon as AnyStyledComponent} />}
</CheckBox>
<CategoryItem key={value.id}>{value.title}</CategoryItem>
</Container>
)
export default ValueItem
在子组件中,如果我使用 export default memo(ValueItem),则复选框不会在单击时更新。
我现在需要的是不要重新渲染每个子组件,但要记住复选框有效。有什么建议吗?
Working Codesandbox
说明
您需要做的是用 React.memo
包裹 child。这样你就可以确保 Child 被记忆并且不会 re-render 不必要的。然而,这还不够。
在 parent 中,handleStateChange
在每次渲染时都会获得一个新的引用,因此它会生成 parent 渲染。如果 parent 呈现,则所有 children 将 re-render。用 useCallback
包装 handleStateChange
确保反应组件记住对函数的引用。 memo
记住了 Child
的结果。
Useful resource
传播 (const temp = { ... keyValueObject }
) 并不像您想象的那样深度克隆对象。所以虽然 keyValueObject
会有一个新的引用,它的对象值不会被克隆,所以会有相同的引用,所以 memo
会认为在比较 category
属性时没有任何变化。
解决方案: 确保为要更新的 keyValueObject
的 ID 创建一个新值。示例:setKeyValueObject(keyValueObject => ({...keyValueObject, [id]: {...keyValueObject[id], isChecked: !keyValueObject[id].isChecked}))
。现在 keyValueObject[id]
是一个新的 object/reference,因此 memo
会看到它并呈现您的组件。它不会渲染其他子项,因为它们的引用保持不变。
我想避免在 <ChildComponent/>
中使用 onClick 更新我的状态时重新渲染我的子组件 <ChildComponent/>
。
我在 <ParentComponent/>
中有我的回调函数,它更新键值对对象的值之一。
在父组件中
const _keyValueObject = useMemo(() => utilityFunction(array, object), [array, object])
const [keyValueObject, setKeyValueObject] = useState<SomeTransport>(_keyValueObject)
const handleStateChange = useCallback((id: number) => {
setKeyValueObject(keyValueObject => {
const temp = { ... keyValueObject }
keyValueObject[id].isChecked = ! keyValueObject[id].isChecked
return temp
})
}, [])
return(
<Container>
{!! keyValueObject &&
Object.values(keyValueObject).map(value => (
<ValueItem
key={value.id}
category={value}
handleStateChange ={handleStateChange}
/>
))}
</Container>
)
在子组件中 ValueItem
const clickHandler = useCallback(
event => {
event.preventDefault()
event.stopPropagation()
handleStateChange(value.id)
},
[handleStateChange, value.id],
)
return (
<Container>
<CheckBox checked={value.isChecked} onClick={clickHandler}>
{value.isChecked && <Icon as={CheckboxCheckedIcon as AnyStyledComponent} />}
</CheckBox>
<CategoryItem key={value.id}>{value.title}</CategoryItem>
</Container>
)
export default ValueItem
在子组件中,如果我使用 export default memo(ValueItem),则复选框不会在单击时更新。
我现在需要的是不要重新渲染每个子组件,但要记住复选框有效。有什么建议吗?
Working Codesandbox
说明
您需要做的是用 React.memo
包裹 child。这样你就可以确保 Child 被记忆并且不会 re-render 不必要的。然而,这还不够。
在 parent 中,handleStateChange
在每次渲染时都会获得一个新的引用,因此它会生成 parent 渲染。如果 parent 呈现,则所有 children 将 re-render。用 useCallback
包装 handleStateChange
确保反应组件记住对函数的引用。 memo
记住了 Child
的结果。
Useful resource
传播 (const temp = { ... keyValueObject }
) 并不像您想象的那样深度克隆对象。所以虽然 keyValueObject
会有一个新的引用,它的对象值不会被克隆,所以会有相同的引用,所以 memo
会认为在比较 category
属性时没有任何变化。
解决方案: 确保为要更新的 keyValueObject
的 ID 创建一个新值。示例:setKeyValueObject(keyValueObject => ({...keyValueObject, [id]: {...keyValueObject[id], isChecked: !keyValueObject[id].isChecked}))
。现在 keyValueObject[id]
是一个新的 object/reference,因此 memo
会看到它并呈现您的组件。它不会渲染其他子项,因为它们的引用保持不变。