首页 > 解决方案 > Array.map 中的 React 功能组件在将函数作为道具传递时总是重新渲染

问题描述

我正在尝试在集中管理所有子状态的父组件中呈现多个按钮。这意味着父级存储例如单击状态,每个按钮在他自己的状态下的禁用状态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/>
})

为了防止子组件重新渲染,我正在使用...

子组件导出为:

export default React.memo(TheChildComponent, compareEquality)

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

不知何故,永远不会执行登录行,compareEquality因此我知道compareEquality永远不会执行。我也不知道为什么会这样。

我检查了所有博客、以前的 Stackoverflow 问题等,但还没有找到一种方法来防止每次至少有一个组件执行该onClick功能并通过这样做更新isSelected状态时重新呈现子组件。

如果有人能指出我正确的方向或解释我的问题来自哪里,我会非常高兴。

提前致谢!

标签: javascriptreactjsreact-hooksreact-functional-component

解决方案


这段代码实际上会在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;
}, []);

结合 vanilla React.memo,这应该可以防止孩子重新渲染,除非发生isSelected变化。(你的第二个论点React.memo应该也解决了这个问题——我不确定为什么这不起作用。)

作为旁注,您可以简化此代码:

     <React.Fragment key={key}>
          <TheChildComponent
               isSelected={isFieldSelected}
               onClick={onClick}
          />
     </React.Fragment/>

到以下:

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

(假设您确实只需要 的主体中的单个组件map)。


推荐阅读