【发布时间】:2020-06-17 02:48:14
【问题描述】:
我试图将问题归结为一个尽可能简单的例子:
我们有一个子组件列表,每个子组件都称为NumChoice,每个子组件代表一个数字。 NumChoice 包裹在 React.memo 中。在父组件中,我们有一个布尔数组choices,每个都对应一个子组件NumChoice。起初,choices 的所有元素都是false。为了渲染子组件,我们遍历choices,并为每个选择生成对应的子组件NumChoice。我们在父组件中定义一个函数chooseDivisibles,使用从每个子组件NumChoice 调用的useCallback。 chooseDivisibles 获取调用它的NumChoice 的索引,并将choices 的对应元素更改为true。每个NumChoice如果choices中对应的元素为true,则其背景颜色为“红色”,否则,其背景颜色为“白色”。
完整的代码可在以下位置获得: https://codesandbox.io/s/react-rerender-l4e3c?fontsize=14&hidenavigation=1&theme=dark
将NumChoice 包装在React.memo 和chooseDivisibles 在useCallback 中,我们希望只重新渲染NumChoice 的组件,其对应的choices 元素发生变化,但React 会重新渲染它们。 chooseDivisibles 被包裹在 useCallback 中,除了 setChoices 之外没有列出任何依赖项。此外,NumChoice 被包裹在 React.memo 中,它应该只在指定的 props 发生变化时重新渲染,但它们不会,并且更改 choices 不应该对重新渲染 NumChoice 产生任何影响。如果我们排除在上一个和下一个道具中检查chooseDivisibles 的相等性,它会按预期工作,但我认为上一个和下一个chooseDivisibles 的比较不应该影响重新渲染NumChoice,因为它包含在useCallbackand不依赖于choices。我们如何防止重新渲染 props 未更改的 NumChoice 组件?
【问题讨论】:
-
在您添加
prevProps.chooseDivisibles === nextProps.chooseDivisiles之前,一切似乎都运行良好,分析器没有显示其 props 保持相同重新渲染的组件。 -
我认为您的建议并不能解决问题,因为如果我们将等式更改为
(prevProps, nextProps) => prevProps === nextProps,它会重新渲染所有组件。考虑到chooseDivisibles被包裹在useCallback中,它列出了除setChoices之外的任何依赖项,因此更改状态不应更改chooseDivisibles并且不应重新渲染NumChoice如果您尝试相同的事情而不使用mapthrough一个数组,这个问题不会发生。请看一下我刚刚保存的新代码。 -
据我所知,React 已经(浅)将以前的 props 与新的 props 对象进行比较,所以这样做
prevProps === newProps是多余的,实际上我认为它是错误的,因为结果将永远是false 不管你是否这样做,因为对象是通过引用传递的。 -
@eMontielG 你的回答是对的。谢谢你。请发布它,我会接受它作为正确答案。为了解决您的问题,我将
chooseDivisibles={event => chooseDivisibles(idx)}更改为chooseDivisibles={chooseDivisibles},并将NumChoice中的函数调用替换为onClick={event => props.chooseDivisibles(props.num)}。然后,我比较了prevProps.num === nextProps.num && prevProps.choice === nextProps.choice && prevProps.chooseDivisibles === nextProps.chooseDivisibles,它按预期工作。 -
顺便说一句,我想我发现了你的问题,你也应该记住循环选择的组件。
标签: reactjs array-map rerender usecallback react-memo