React Array中的功能组件.当传入一个函数作为道具时,Map总是被重新渲染



我试图在集中管理所有子状态的父组件中呈现多个按钮。这意味着父进程使用useState将每个按钮的点击状态、禁用状态等保存在自己的状态中,并将其作为道具传递给子进程。此外,onClick函数也在父组件内部定义,并向下传递给每个子组件。目前,我正在这样做:

const [isSelected, setIsSelected] = useState(Array(49).fill(false));
...
const onClick = useCallback((index) => {
const newIsSelected = [...prev];
newIsSelected[i] = !newIsSelected[i];
return newIsSelected;
}, []);
...
(In the render function:)
return isSelected.map((isFieldSelected, key) => {
<React.Fragment key={key}>
<TheChildComponent
isSelected={isFieldSelected}
onClick={onClick}
/>
</React.Fragment/>
})

为了防止子组件重新渲染,我使用…

  • useCallback使反应看到onClick功能始终保持不变
  • React.Fragment使react再次找到组件,否则子组件将没有唯一的id或类似的东西

子组件导出为:

export default React.memo(TheChildComponent, compareEquality)with

const compareEquality = (prev, next) => {
console.log(prev, next);
return prev.isSelected === next.isSelected;
}

不知何故compareEquality中的日志行从未执行过,因此我知道compareEquality从未执行过。我也不知道为什么会这样。

我已经检查了所有的博客,以前的Stackoverflow问题等,但还没有找到一种方法来防止子组件被重新渲染,每次至少有一个组件执行onClick函数,并通过这样做更新了isSelected状态。

如果有人能给我指出正确的方向或解释我的问题从何而来,我将非常高兴。

提前感谢!

这段代码实际上将在每次渲染时生成一个新的onClick函数,因为useCallback没有给定一个deps数组:

const onClick = useCallback((index) => {
const newIsSelected = [...prev];
newIsSelected[i] = !newIsSelected[i];
return newIsSelected;
});

下面应该只创建一个onClick函数,并在所有渲染中重用它:

const onClick = useCallback((index) => {
const newIsSelected = [...prev];
newIsSelected[i] = !newIsSelected[i];
return newIsSelected;
}, []);

与香草React.memo相结合,这应该可以防止子渲染,除非isSelected发生变化。(你对React.memo的第二个论点应该也解决了这个问题——我不知道为什么不工作。)

作为旁注,您可以简化这段代码:
<React.Fragment key={key}>
<TheChildComponent
isSelected={isFieldSelected}
onClick={onClick}
/>
</React.Fragment/>

到下面:

<TheChildComponent key={key}
isSelected={isFieldSelected}
onClick={onClick}
/>

(假设您确实只需要在map的主体中使用一个组件)。

事实证明,唯一的问题既不是useCallback,也不是useMemo或任何类似的东西。

在父组件的渲染函数中,我没有直接使用

return isSelected.map(...)

我从一个单独的,非常简单的组件中包含了这个部分,就像这样:

const Fields = () => {
return isSelected.map((isFieldSelected, i) => (
<TheChildComponent
key={i}
isSelected={isFieldSelected}
onClick={onClick}
/>
));
};

这就是我的问题所在。当将代码从单独的组件Fields移动到父组件的返回语句中时,重呈现错误就消失了。

还是谢谢你的帮助。

最新更新