如何避免在父组件状态更新时重新渲染循环中的所有子组件

2023-12-20

我有一个子组件,它位于父组件的循环内。当子组件之一更新父组件的状态时,它会重新渲染所有子组件,因为它是循环的。我怎样才能避免每次迭代的重新渲染。


function Parent() {
  const [selectedChild, setSelectedChild] = useState([]);

  const onChangeHandle = (event, id) => {
    const checked = event.target.checked;
      let updatedArray = [...selectedChild];
      if(checked){
         if(!selectedChild.includes(id)){
            updatedArray.push(id); 
         }
      }
      else{
         var index = updatedArray.indexOf(id)
         if (index !== -1) {
            updatedArray.splice(index, 1);
         }
      }
      setSelectedChild(updatedArray);
  }
  const dummy = (id) => {
    return selectedChild.includes(id);
  }
  return (
    <div>
    <table>
    <tbody>
      {[1,2,3].map((value, index) => {
      return (
        <Child 
        key={index} 
        index={index} 
        value={value} 
        handle={onChangeHandle}
        isSelected={dummy}
        />
      )
      })}
    </tbody>
    </table>
    <div>
      {selectedChild}
    </div>
  </div>)
}

function Child({index, value, handle, isSelected }) {
  console.log('rendering')

 return (
 <tr>
    <td>
      <input 
      type="checkbox" 
      checked={isSelected(index)}
      onChange={(event) => handle(event, index)}/>
    </td>
    <td>hello {index} {value}</td>
 </tr>
 )
}

export default function App() {
  return (
    <div className="App">
      <Parent />
    </div>
  );
}

当前行为:在上面的代码中,当我单击子组件之一中的复选框时,它正在更新父组件状态(selectedChild)。因此循环正在执行,所有子项(所有表行)都在重新渲染。

预期行为:只有特定的行需要重新渲染

Demo: https://codesandbox.io/s/newpro-0pezc https://codesandbox.io/s/newpro-0pezc


为此你可以使用React.memo https://pt-br.reactjs.org/docs/react-api.html#reactmemo如果 props 保持不变,这将记住你的组件。但鉴于您的代码,您需要进行一些额外的更改:

  • 你必须申请useCallback记住 onChangeHandle 函数;

  • 要正确记住 onChangeHandle,您需要重构它。你不能通过selectedChild直接,否则它会记住它的值。使用setSelectedChild传递一个函数作为参数,该函数接受selectedChild反而。

  • 您的孩子应该收到isSelected作为布尔值而不是函数。否则 props 将保持不变并且 Child 永远不会更新;

    import React, { useState, memo, useCallback } from "react";
    
    function Parent() {
      const [selectedChild, setSelectedChild] = useState([]);
    
      const onChangeHandle = useCallback((event, id) => {
        setSelectedChild(selectedChild => {
          const checked = event.target.checked;
          let updatedArray = [...selectedChild];
          if (checked) {
            if (!selectedChild.includes(id)) {
              updatedArray.push(id);
            }
          } else {
            var index = updatedArray.indexOf(id);
            if (index !== -1) {
              updatedArray.splice(index, 1);
            }
          }
          return updatedArray;
        });
      }, []);
    
      const dummy = id => {
        return selectedChild.includes(id);
      };
    
      const renderChildren = () =>
        [1, 2, 3].map((value, index) => {
          return (
            <Child
              key={index}
              index={index}
              value={value}
              handle={onChangeHandle}
              isSelected={dummy(index)}
            />
          );
        });
    
      return (
        <div>
          <table>
            <tbody>{renderChildren()}</tbody>
          </table>
          <div>{selectedChild}</div>
        </div>
      );
    }
    
    const Child = memo(({ index, value, handle, isSelected }) => {
      console.log("rendering");
    
      return (
        <tr>
          <td>
            <input
              type="checkbox"
              checked={isSelected}
              onChange={event => handle(event, index)}
            />
          </td>
          <td>
            hello {index} {value}
          </td>
        </tr>
      );
    });
    
    export default function App() {
      return (
        <div className="App">
          <Parent />
        </div>
      );
    }
    

https://stackblitz.com/edit/so-memo-children?file=src/App.js https://stackblitz.com/edit/so-memo-children?file=src/App.js

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

如何避免在父组件状态更新时重新渲染循环中的所有子组件 的相关文章

随机推荐

  • firebase 和 swift - 此类不符合键值编码 -----

    我知道还有其他类似的问题 但我认为我的问题是如何访问 firebase 而不是插座 因为我的错误位于 IBAction 函数中 该函数可以在错误发生之前调用 IBAction func sign in out tapped sender U
  • 使用 DSC Resource 配置 HKEY_CURRENT_USER 实际上会更新 HKEY_USERS\.DEFAULT

    以下 DSC 声明写入注册表项 HKEY USERS DEFAULT Console 而不是 HKEY CURRENT USER Console 为什么 Registry ConsoleFaceName Key HKEY CURRENT U
  • 从字符串向量中提取第 n 个字符[重复]

    这个问题在这里已经有答案了 我有一个行向量 如下所示 1 118 o m n a jpg 2 122 m f h a jpg 3 152 y f n a jpg 4 160 y m h a jpg 5 083 o m a a jpg 例如
  • Asp.Net SQL刷新页面重复插入?

    我有一个 aspx 页面 其中包含一个文本框和一个按钮 当用户在文本框中输入信息并单击 发布 时 它会将数据插入到我的 sql 数据库中 问题是 如果用户点击刷新 它将继续将相同的数据插入数据库 我很确定调用了整个 单击 方法 而不仅仅是插
  • 将多个字符串传递给 SharedPreferences

    我想存储三个字符串作为我的应用程序的用户首选项 我已经设置了一个很好的布局 只需将字符串保存到 SharedPreferences 即可 我还想知道如何在下一个活动中检索这些字符串 下面是我当前的代码 如果有人可以向我展示如何将此功能添加到
  • Java Web Start应用程序可以从本地系统读取文件,但不能写入[关闭]

    Closed 这个问题是无法重现或由拼写错误引起 help closed questions 目前不接受答案 请询问您是否需要更多信息 我有安全和所有权限标签 在我的 jnlp 中 当我离线运行我的 java 应用程序时 它可以正常工作 F
  • AWS API Gateway 和 Lambda 的公共 IP 地址(无 VPC)

    我已经配置了一个 AWS API Gateway 并创建了一个 Lambda 函数来连接到外部 REST API API网关和Lambda不在VPC中 因此出口IP地址是随机的 我面临的挑战是外部 REST API 位于防火墙后面 这需要将
  • 如何在 GDScript 中实现结构?

    GDScript 中是否有相当于 C 结构 类的东西 例如 struct Player string Name int Level 戈多3 1 1gdscript不支持structs 但使用可以实现类似的结果classes dict or
  • Windows 7 64 / Visual Studio 2008 / OpenCV2.1错误:“应用程序无法正确启动(0xhex)..”

    我正在 64 位模式下从分支顶部构建 OpenCV2 1 当我将库链接到我的代码 在 XP 上以 32 位模式工作 时 我收到对话框 应用程序无法正确启动 0xc0150002 单击 确定 关闭应用程序 当我启动应用程序时 事件查看器指向
  • 将一个时间范围按其他时间范围分割成多个部分

    我有一项复杂的任务 几天来我一直在用头撞墙 我已经尝试了大约 4 种不同的方法 但是每种方法似乎都停滞不前 并且变得非常令人沮丧 我有一个时间范围 例如 14 30 00 至 18 30 00 考虑某人轮班的时间范围 在此时间范围内 他们表
  • jasmine 与 jscoverage 自动化测试

    一直在看 jsunit 和 jcoverage 演示 单击覆盖率报告链接 在新选项卡中打开此内容 我想知道是否有人对 Jasmine 和 JSCoverage 做过类似的事情 我有点不确定如何继续 编辑 我想知道有什么可以和茉莉花记者一起做
  • fopen b 标志是什么

    在阅读中php fopen 的文档 http php net manual en function fopen php对于 php 我看到以下内容 为了可移植性 强烈建议您在使用以下命令打开文件时始终使用 b 标志fopen http ph
  • 某些 lua/c++ 代码中出现 SIGSEGV 错误

    以下代码以 SIGSEGV 错误结束 extern C include lua lua h include lua lualib h include lua lauxlib h int main int argc char argv lua
  • 创建具有左偏概率分布的随机数

    我想在 1 100 之间随机选择一个数字 这样获得数字 60 100 的概率高于 1 59 我希望数字 1 100 的概率为左偏分布 也就是说 它有一个长尾和一个峰 大致意思是 pers np arange 1 101 1 prob
  • 在 IF ELSE 块中包含 InstallDir

    我尝试使用以下代码 The default installation directory InstallDir PROGRAMFILES PRODUCT NAME to include x64 nsh If RunningX64 The d
  • css 中的图像轮播无法正常工作

    我正在制作一个网站的轮播 但宽度有问题 我希望每个图像都占据视口的整个宽度 但最后一个图像出现在第一个图像的下方 即使滑块动画也无法通过在右侧滑动额外内容来正确滑动图像 任何帮助 将不胜感激 carousel container carou
  • 将 Angular2 应用程序包含到 Asp.Net Webforms 页面

    当我将 angular cli ng build 生成的带有 aot 配置的 js 文件包含到我的 aspx 页面中时 我在 Chrome 控制台中收到一条错误消息 gt TypeError Error parameterCount is
  • 函数式语言对于飞行模拟器来说是一个不错的选择吗? Lisp 怎么样?

    我做面向对象编程也有几年了 函数式编程做的不多 我对飞行模拟器很感兴趣 并且对 Lisp 的函数式编程方面感到好奇 在面向对象的范例中 飞行模拟器或任何其他现实世界模拟器对我来说都是有意义的 这是我的问题 面向对象是表示现实世界模拟领域的最
  • .node 不是有效的 Win32 应用程序

    在 Window 10 Home x64 位 上 我尝试在命令提示符下运行以下命令 节点索引 js 错误如下 C Users cooldudeasateen OneDrive Coding sil node modules bindings
  • 如何避免在父组件状态更新时重新渲染循环中的所有子组件

    我有一个子组件 它位于父组件的循环内 当子组件之一更新父组件的状态时 它会重新渲染所有子组件 因为它是循环的 我怎样才能避免每次迭代的重新渲染 function Parent const selectedChild setSelectedC