Antd Table组件,state改变,但是render并不会重新渲染

背景

在table上面,当鼠标放在cell上面的时候,需要去请求接口拉取数据,然后setList(res.result)后,希望render中的traceIds也能够实时更新渲染。在这里插入图片描述

const [traceIds, setTraceIds] = useState() // 需要展示在popover上面的数据,接口返回

const renderErrorCodeList = useMemoizedFn((errors: MttkError[], record: MttkInfo) => {
  return (
    <ul className="table-error-code-ul">
      {errors?.length
        ? errors?.map((err) => {
            const msg = err.error_message?.map((e) => e.message)?.join(';');
            return (
              <li key={err.code}>
                <Popover
                  placement="top"
                  content={{loading?'loading...':traceIds}} // 关键点,当list改变的时候,这里的popover并不会重新渲染
                  trigger="hover"
                  title="Detail"
                  overlayClassName="trace-detail-popover"
                  overlayStyle={{ width: 500 }}
                >
                  <a
                    onMouseEnter={() => {
                      // 避免鼠标来回滑入滑出,造成接口的调用
                      // 希望用户能够将鼠标停留在链接上面之后,再唤起接口和popover
                      timer.current = setTimeout(() => {
                        // 获取接口数据...
                        setTraceIds(res.data);
                      }, 1000);
                    }}
                  >
                    {`${err.code}${msg ? `(${msg})` : ''}`}
                  </a>
                </Popover>
              </li>
            );
          })
        : '-'}
    </ul>
  );
});

const columns = [
  {
    title: 'Top Error Codes',
    dataIndex: 'top_error',
    width: 500,
    render: (errors: MttkError[], record: MttkInfo) => renderErrorCodeList(errors, record),
  },
  {
    title: 'QPS',
    dataIndex: 'qps',
  },
];

<Table
  columns={columns}
  dataSource={data}
  size="small"
/>

原因:state改变并不会触发render重新渲染。

参考:https://github.com/ant-design/ant-design/issues/35820、
https://github.com/ant-design/ant-design/issues/418

解决方法

(1)考虑前端自定义一个变量list,当接口返回数据后,我们手动修改datasource的数据
(2)利用 shouldCellUpdate 实时更新当前单元格

export default function InfoTable(props: Props) {
  const { dataSource, timestamp, azKey } = props;
  const timer = useRef<number>();
  const [data, setData] = useState<MttkInfo[]>([]); // datasource

  const jumpToTracingPage = (traceId: string) => {
    window.open(`${basePath}/tracing?traceId=${traceId}`);
  };

  const { run: getTraceList } = useDebounceFn(
    async (code: string, record: MttkInfo, latency?: number) => {
      try {
          // 请求接口...
          const res = await getTraceIdListByCode(params);

          const newData = data?.map((info) => {
            if (info.id === record.id) {
              return { ...info, traceIds: res?.data, isCallEnd: Math.random() }; // 关键点
            }
            // 对于没有命中的record,重置traceIds,方便判断是否展示 loading
            return { ...info, traceIds: undefined };
          });

          setData(newData);
        }
      } catch (err) {
        console.error(err);
      }
    },
    {
      wait: 500,
    },
  );

  const getErrorInfo = (error: MttkError) => {
    return <div>其他固定信息...</div>
  };

  const renderTraceListContent = (traceIds?: string[]) => {
    let content: ReactNode = '';

// 关键点:判断状态
    if (traceIds === undefined) {
      content = 'Loading...';
    } else if (traceIds?.length === 0) {
      content = 'Not found';
    } else {
      content = (
        <ul style={{ paddingLeft: 15 }}>
          {traceIds?.map((id) => (
            <li key={id}>
              <a onClick={() => jumpToTracingPage(id)}>{id}</a>
            </li>
          ))}
        </ul>
      );
    }

    return content;
  };

  const renderErrorCodeList = useMemoizedFn((errors: MttkError[], record: MttkInfo) => {
    const { traceIds = undefined } = record;
    const content = renderTraceListContent(traceIds); // 获取trace id列表

    return (
      <ul className="table-error-code-ul">
        {errors?.length
          ? errors?.map((err) => {
              const baseInfo = getErrorInfo(err);
              const msg = err.error_message?.map((e) => e.message)?.join(';');
              return (
                <li key={err.code}>
                  <Popover
                    placement="top"
                    content={
                      <>
                        {baseInfo}
                        <div style={{ fontSize: 12 }}>{content}</div>
                      </>
                    }
                    trigger="hover"
                    title="Detail"
                    overlayClassName="trace-detail-popover"
                    overlayStyle={{ width: 500 }}
                  >
                    <a
                      onMouseEnter={() => {
                        // 避免鼠标来回滑入滑出,造成接口的调用
                        // 希望用户能够将鼠标停留在链接上面之后,再唤起接口和popover
                        timer.current = setTimeout(() => {
                          getTraceList(err.code, record);
                        }, 1000);
                      }}
                      onMouseLeave={() => {
                        clearTimeout(timer.current);
                        // 对于同一个单元格,如果有多个code,重复点击同一个单元格的时候,会造成一直显示上次的内容。所以在鼠标移出后,需要重置traceIds为undefined
                        // 或者同一行来回移动,popover还是会保持上一次的内容
                        setData(data?.map((info) => ({ ...info, traceIds: undefined })));
                      }}
                    >
                      {`${err.code}${msg ? `(${msg})` : ''}`}
                    </a>
                  </Popover>
                </li>
              );
            })
          : '-'}
      </ul>
    );
  });

  const columns = [
    {
      title: 'Top Error Codes',
      dataIndex: 'top_error',
      width: 500,
      render: (errors: MttkError[], record: MttkInfo) => renderErrorCodeList(errors, record),
      shouldCellUpdate: (record: MttkInfo, pre: MttkInfo) => record?.isCallEnd !== pre?.isCallEnd, // 关键点,表示请求结束了,需要重新渲染当前单元格
    },
    {
      title: 'QPS',
      dataIndex: 'qps',
    },
  ];
  return (
    <Table
      columns={columns}
      dataSource={data}
      size="small"
    />
  );
}

但是上面的处理方法存在一个问题:

(1)如果在同一行来回移动,popover展示的是上一次的信息
(2)如果在当前单元格内上下移动(比如有多个li元素),popover展示的是上一次的信息

希望能够找到优化方式…


或者考虑使用 useUpdate hooks,在需要setState重新渲染的时候,调一下它??但是会造成表格的所有数据都被重新渲染

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/608533.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

基于STM32F401RET6智能锁项目(环境搭建)

工程搭建 MDK&#xff0c;固件库&#xff0c;芯片包下载 下载keil5&#xff0c;stm32f4xx的固件库以及stm32f4的芯片包 keil官网&#xff1a;https://www2.keil.com/mdk5/ stm32中国官网&#xff1a;https://www.stmcu.com.cn/ 创建工程 1、新建一个工程文件夹&#xff0c;…

漫威争锋Marvel Rivals怎么搜索 锁区怎么搜 游戏搜不到怎么办

即将问世的《漫威争锋》&#xff08;Marvel Rivals&#xff09;作为一款万众期待的PvP射击游戏新星&#xff0c;荣耀携手漫威官方网站共同推出。定档5月11日清晨9时&#xff0c;封闭Alpha测试阶段将正式揭开序幕&#xff0c;持续时间长达十天之久。在此首轮测试窗口&#xff0c…

加速科技突破2.7G高速数据接口测试技术

随着显示面板分辨率的不断提升&#xff0c;显示驱动芯片&#xff08;DDIC&#xff09;的数据接口传输速率越来越高&#xff0c;MIPI、LVDS/mLVDS、HDMI等高速数据接口在DDIC上广泛应用。为满足高速数据接口的ATE测试需求&#xff0c;作为国内少数拥有完全自研的LCD Driver测试解…

Facebook消息群发脚本的制作思路!

在数字化社交日益盛行的今天&#xff0c;Facebook作为全球最大的社交平台之一&#xff0c;为企业和个人提供了广阔的交流与合作空间。 然而&#xff0c;手动向大量用户发送消息既耗时又低效&#xff0c;因此&#xff0c;开发一款能够自动群发消息的脚本成为了许多人的需求&…

JavaWeb之Servlet(上)

前言 1. 什么是Servlet (1) Servlet介绍 (2) Servlet运行于支持Java的应用服务器中。 (3) Servlet工作模式&#xff1a; 2. Servlet API 3. 第一个Servlet (1) 创建一个类实现Servlet接口,重写方法。或继承HttpServlet亦可 (2) 在web.xml文档中配置映射关系 标签的执行…

48. UE5 RPG 实现攻击伤害数字显示

在前面的文章中&#xff0c;我们实现了对敌人的攻击的受击效果&#xff0c;并且能够降低目标的血量&#xff0c;实现死亡效果。相对于正常的游戏&#xff0c;我们还需要实现技能或者攻击对敌人造成的伤害数值&#xff0c;并直观的显示出来。 所以&#xff0c;接下来&#xff0c…

电商核心技术揭秘52:数字化内容营销创新

相关系列文章 电商技术揭秘相关系列文章合集&#xff08;1&#xff09; 电商技术揭秘相关系列文章合集&#xff08;2&#xff09; 电商技术揭秘相关系列文章合集&#xff08;3&#xff09; 电商技术揭秘四十一&#xff1a;电商平台的营销系统浅析 电商技术揭秘四十二&#…

通过Docker Compose部署GitLab和GitLab Runner(一)

GitLab 是一个用于版本控制、项目管理和持续集成的开源软件平台&#xff0c;它提供了一整套工具&#xff0c;能够帮助团队高效地协作开发。而 GitLab Runner 则是 GitLab CI/CD 的执行者&#xff0c;用于运行持续集成和持续交付任务。 在本文中&#xff0c;我们将使用 Docker …

虚拟机装CentOS镜像

起先&#xff0c;是先安装一个VM虚拟机&#xff0c;再去官方网站之类的下载一些镜像&#xff0c;常见镜像有CentOS镜像&#xff0c;ubantu镜像&#xff0c;好像还有一个树莓还是什么的&#xff0c;软件这块&#xff0c;日新月异&#xff0c;更新太快&#xff0c;好久没碰&#…

C程序内存分布及static变量

C程序内存分布及static变量 C语言中程序的内存分布 [&#x1f517;1](https://www.cnblogs.com/miaoxiong/p/11021827.html)[&#x1f517;2](https://blog.csdn.net/chen1083376511/article/details/54930191)c/c编译连接后二进制文件的存储动静态存储方式和存储区动态存储方式…

贪心算法--将数组和减半的最小操作数

本题是力扣2208---点击跳转题目 思路&#xff1a; 要尽快的把数组和减小&#xff0c;那么每次挑出数组中最大的元素减半即可&#xff0c;由于每次都是找出最值元素&#xff0c;可以用优先队列来存储这些数组元素 每次取出最值&#xff0c;减半后再放入优先队列中&#xff0c;操…

Centos7使用kubeadm搭建k8s集群(一主两从)----(mac版)

一、环境准备 1、下载centos7镜像 阿里巴巴开源镜像站-OPSX镜像站-阿里云开发者社区 下载地址: centos安装包下载_开源镜像站-阿里云 选择对应的版本即可&#xff0c;我下载的&#xff1a;CentOS-7-x86_64-DVD-2207-02.iso 2、使用VirtualBox安装centos 选择新建&#xff0c…

Rust 通用代码生成器莲花,红莲尝鲜版二十三,多对多候选,增强数据库反射项目功能

Rust 通用代码生成器莲花&#xff0c;红莲尝鲜版二十三&#xff0c;此版本新增了多对多候选功能&#xff0c;增强了数据库自动反射功能和模板向导的编辑器。请部署在 Tomcat9 的 webapps 目录下。 多对多候选功能大大增强了一个数据库自动反射成一个项目的功能&#xff0c;它可…

Docx文件误删除如何恢复?别再花冤枉钱了,4个高效恢复软件!

不管是工作还是学习&#xff0c;总是会与各种各样的文件打交道。文件量越多就越容易出现文件丢失、文件误删的情况。遇到这些情况&#xff0c;失去的文件还能找回来吗&#xff1f;只要掌握了一些数据恢复方法&#xff0c;是很有机会恢复回来的&#xff0c;下面我会将这些方法分…

MacBook Pro(Intel集成显卡)成功安装启动ComfyUI详细教程

Mac配置 MAC CPU: 2.2 GHz 四核Intel Core i7MAC 系统版本&#xff1a;12.3MAC 显卡&#xff1a; Intel Iris Pro 1536 MBMAC 内存&#xff1a;16Gpython 3.12.2 ComfyUI 的安装方法介绍 ComfyUI 是一个模块化的 Stable Diffusion GUI&#xff0c;工作界面是可视化的流程节点…

图神经网络——GCN,GraphSAGE

1、应用 生物化学&#xff1a;分子指纹识别、药物分子设计、疾病分类等 交通领域&#xff1a;对交通需求的预测、对道路速度的预测 计算机图像处理&#xff1a;目标检测、视觉推理等 自然语言处理&#xff1a;实体关系抽取、关系推理等 2、数据集介绍 CORA数据集由2708篇论文&…

影视极品转场音效大全,经典获奖通用音效素材

一、素材描述 本套音效素材&#xff0c;大小15.02G&#xff0c;16个压缩文件。 二、素材目录 01-华纳兄弟电影音效库合辑&#xff08;2个压缩文件&#xff09; 02-影视极品转场音效&#xff08;2个压缩文件&#xff09; 03-好莱坞经典综合音效&#xff08;4个压缩文件&…

线程安全问题、同步代码块、同步方法

线程安全问题就是 用线程同步来解决线程安全问题 同步&#xff1a;一个线程接着一个线程等待执行 同步代码块&#xff1a; 通过锁来解决卖到重复票的问题&#xff1a;卖票问题和存钱取钱问题&#xff08;见其他两篇文章&#xff09; 同步方法&#xff1a;

杨辉三角的打印

题目内容&#xff1a; 在屏幕上打印杨辉三角。 思路&#xff1a; 首先我们通过观察发现&#xff0c;每一步的打印都与行列数有关&#xff0c;中间的数据由这一列和上一行的前一列数据控制。所以我们可以使用二维数组进行操作&#xff1a; &#xff08;&#xff11;&#xff…

用Rust解决鸡兔同笼问题

目录 一、什么是鸡兔同笼问题&#xff1f; 二、用Rust解决鸡兔同笼问题 三、鸡兔同笼问题在实际生活中的应用有哪些&#xff1f; 一、什么是鸡兔同笼问题&#xff1f; 鸡兔同笼问题是一种古代著名的数学问题&#xff0c;用于训练逻辑思维和解决方程的能力。 鸡兔同笼问题起…