react-window构造的虚拟列表使用react-resizable动态调整宽度和使用react-drag-listview拖拽变换列位置的问题

news2025/1/18 0:36:31

文章目录

    • react-window构造的虚拟列表使用react-resizable动态调整宽度和使用react-drag-listview拖拽变换列位置的问题
      • 需求
      • 问题
      • 问题根源
      • 部分代码
      • 参考

react-window构造的虚拟列表使用react-resizable动态调整宽度和使用react-drag-listview拖拽变换列位置的问题

需求

项目中使用react-windowVariableSizeGrid构造虚拟列表来解决大型的数据列表渲染的性能问题。虚拟列表的优点是不用全部加载出所有的DOM节点, 而是按需显示思路的一种实现,即虚拟列表是一种根据滚动容器元素的可视区域来渲染长列表数据中某一个部分数据的技术。具体关于虚拟列表的使用和原理这里就不过多赘述了。

ant design官网中就是使用react-window去构造虚拟列表的

在这里插入图片描述

然后我们的需求是,想要react-resizable去动态调整table(虚拟列表)的列宽度,还有使用react-drag-listview拖拽变换列位置。关于具体实现,这里不过多介绍,网上有很多参考的例子:Ant Design + react-drag-listview实现Table拖拽变换列位置

问题

然而在实际开发中发现,对于普通Table(非虚拟列表)是生效的,能够动态的改变列的宽度和位置,然而对虚拟列表却无法变化。

问题根源

VariableSizeGrid 会遇到虚拟列表项样式缓存没有被清除导致和第一次可视区域里展示的一样。

我们可以看到VariableSizeGrid中的两个API

 /**
     * VariableSizeGrid caches offsets and measurements for each column index for performance purposes.
     * This method clears that cached data for all columns after (and including) the specified index.
     * It should be called whenever a column's width changes. (Note that this is not a typical occurrence.)
     *
     * By default the grid will automatically re-render after the index is reset.
     * If you would like to delay this re-render until e.g. a state update has completed in the parent component,
     * specify a value of false for the second, optional parameter.
     */
    resetAfterColumnIndex(index: number, shouldForceUpdate?: boolean): void;
    
     /**
     * VariableSizeGrid caches offsets and measurements for each row index for performance purposes.
     * This method clears that cached data for all rows after (and including) the specified index.
     * It should be called whenever a row's height changes. (Note that this is not a typical occurrence.)
     *
     * By default the grid will automatically re-render after the index is reset.
     * If you would like to delay this re-render until e.g. a state update has completed in the parent component,
     * specify a value of false for the second, optional parameter.
     */
    resetAfterRowIndex(index: number, shouldForceUpdate?: boolean): void;

大概意思就是出于性能优化的目的,VariableSizeGrid会缓存列表的行高和列框, 所以当我们调整了列的宽度,但是却没有清楚掉这些缓存,就会导致虚拟列表不会渲染出来最新的样式。

所以我们可以手动调用这两个API来达到动态调整宽度和变化列位置。

部分代码

其中核心代码是下面这句

const refreshVirtualTable = ()=>{
    if (gridRef?.current) {
      (gridRef.current as any)?.resetAfterRowIndex(0);
      (gridRef.current as any)?.resetAfterColumnIndex(0);
    }
  }

下面给出部分代码

import React, {useEffect, useLayoutEffect, useRef, useState} from 'react';
import 'antd/dist/antd.css';
import './index.css';
import {VariableSizeGrid as Grid} from 'react-window';
import classNames from 'classnames';
import ResizeObserver from 'rc-resize-observer';
import DragTable from "@/components/common/DragTable";

function VirtualTable(props: any) {
  const normalRowHeight = 25;
  const {columns, scroll, rowHeight} = props;
  const [tableWidth, setTableWidth] = useState(0);
  const gridRef = useRef(null);
  const [mergedColumns, setMergedColumns] = useState<any[]>([]);
  const refreshVirtualTable = ()=> { //核心代码
    if (gridRef?.current) {
      (gridRef.current as any)?.resetAfterRowIndex(0);
      (gridRef.current as any)?.resetAfterColumnIndex(0);
    }
  }

  useLayoutEffect(() => {
    setMergedColumns(columns.map((column: any) => {
      return column;
    }));
    refreshVirtualTable();
  }, [columns])

  useEffect(() => {
    refreshVirtualTable();
  }, [rowHeight])

  const renderCell = (columnIndex: number, rowIndex: number, rawData: any[][]) => {
    return mergedColumns[columnIndex].render(
      rawData[rowIndex][mergedColumns[columnIndex].dataIndex],
      rawData[rowIndex], rowIndex
    )
  }

  const calculateTableHeight = (rowLengths: number): number => {
    if (rowLengths * (rowHeight || normalRowHeight) > scroll.y) {
      return scroll.y;
    } else {
      let columnTotalWidth = 0;
      mergedColumns.forEach((element: any) => {
        columnTotalWidth += element.width;
      })
      return rowLengths * (rowHeight || normalRowHeight) + (columnTotalWidth > tableWidth ? 18 : 0)
    }
  }

  const renderVirtualList = (rawData: any[][], {onScroll}: any) => {
    const totalHeight = rawData.length * (rowHeight || normalRowHeight);
    return (
      <Grid ref={gridRef}
            className="virtual-grid"
            columnCount={mergedColumns.length}
            columnWidth={(index) => {
              const {width} = mergedColumns[index];
              return totalHeight > scroll.y && index === mergedColumns.length - 1
                ? width - 15
                : width;
            }}
            height={calculateTableHeight(rawData.length)}
            rowCount={rawData.length}
            rowHeight={() => rowHeight || normalRowHeight}
            width={tableWidth}
            onScroll={({scrollLeft}) => {
              onScroll({
                scrollLeft,
              });
            }}
      >
        {({columnIndex, rowIndex, style}) => (
          <div
            className={classNames({
                'zebra-odd': rowIndex % 2 !== 0
              }, 'virtual-table-cell', {
                'virtual-table-cell-last':
                  columnIndex === mergedColumns.length - 1,
              }
            )}
            style={style}
          >
            {
              renderCell(columnIndex, rowIndex, rawData)
            }
          </div>
        )}
      </Grid>
    );
  };

  const onColumnChange = (column: any[]) => {
    setMergedColumns(column);
    refreshVirtualTable();
  }


  return (
    <ResizeObserver
      onResize={({width}) => {
        setTableWidth(width);
      }}
    >
      <DragTable
        {...props}
        onColumnChange={onColumnChange}
        className={"virtual-table common-table"}
        columns={columns}
        pagination={false}
        components={{
          body: renderVirtualList,
        }}
      />
    </ResizeObserver>
  );
}

export default VirtualTable;

参考

Ant Design + react-drag-listview实现Table拖拽变换列位置

Ant Design + react-resizable实现列表页可拖拽宽度变化

使用react-window构造虚拟列表(性能优化)

mini react-window(二) 实现可知变化高度虚拟列表

长列表优化:用 React 实现虚拟列表

浅说虚拟列表的实现原理

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

java项目-第154期ssm足球赛会管理系统-ssm毕业设计_计算机毕业设计

java项目-第154期ssm足球赛会管理系统-ssm毕业设计_计算机毕业设计 【源码请到资源专栏下载】 今天分享的项目是《ssm足球赛会管理系统》 该项目分为2个角色&#xff0c;管理员、用户。 用户可以浏览前台,包含功能有&#xff1a; 首页、球队介绍、球星介绍、线下足球、赛论坛信…

Revit中项目的正负零零,尺寸标注,标注生成问题

一、 Revit中如何改变项目的正负零零 有时候&#xff0c;在一个项目中&#xff0c;我们要改变项目的 正负零零&#xff0c;如下图 第一步&#xff0c;打开视图的“可见性/图形”&#xff0c;如图2 第二步&#xff0c;在“可见性/图形替换”中勾选“项目基点”&#xff0c;如图 …

TK爆品剖析 水晶首饰降临节日历持续火爆TikTok,独立站卖到断货

圣诞节是年末促销旺季的关键节点&#xff0c;很多商家都会推出圣诞主题礼物产品&#xff0c;比如圣诞树、圣诞贺卡、圣诞老人等等&#xff0c;但很少会推出降临节日历。 其实&#xff0c;“降临节日历”一直是人们在圣诞节前最喜欢的礼物。谷歌趋势显示&#xff0c;2021年圣诞节…

[Spring Cloud] Ribbon介绍与定义负载均衡

✨✨个人主页:沫洺的主页 &#x1f4da;&#x1f4da;系列专栏: &#x1f4d6; JavaWeb专栏&#x1f4d6; JavaSE专栏 &#x1f4d6; Java基础专栏&#x1f4d6;vue3专栏 &#x1f4d6;MyBatis专栏&#x1f4d6;Spring专栏&#x1f4d6;SpringMVC专栏&#x1f4d6;SpringBoot专…

QXlsx 使用

QXls使用分两种方式&#xff1a; 1 直接加载pri文件&#xff0c;就可以使用&#xff1b;2 编译后作为Qt的模块加载使用&#xff1b; 此文章主要针对第二种使用方式做记录&#xff0c;该方式又分为两种编译器进行说明&#xff1a; 第一种&#xff0c;使用MinGW64位编译器&…

nginx部署web项目(跟着搞不出来,来砍我)

前端打包成dist&#xff0c;详情可以参考我的vue博客 vue速学_我要用代码向我喜欢的女孩表白的博客-CSDN博客 nginx下载地址:nginx1.16.1离线安装包_nginx1.16.1依赖-Web服务器文档类资源-CSDN下载 &#xff08;如果报错缺少依赖&#xff0c;可以参考我的nginx-rtmp直播流博客…

文献阅读01_基于深度学习的个性化新闻推荐方法研究_20221114

论文信息 Subjects:新闻推荐;长短期用户表示;多视角学习;联合学习; &#xff08;1&#xff09;题目&#xff1a;Attention Is All You Need &#xff08;你需要的就是关注&#xff09; &#xff08;2&#xff09;文章下载地址&#xff1a;https://kreader.cnki.net/Kreader/Ca…

行业安全解决方案|腾讯打造汽车一体化安全防护,助力车企数字化安全

随着汽车智能化的发展&#xff0c;车联网、自动驾驶、车路协同等应用快速落地&#xff0c;汽车作为智能终端所产生的数据成指数级增长态势。然而&#xff0c;当汽车行业数字化转型正如火如荼进行时&#xff0c;新的安全挑战也接踵而至&#xff0c;车企甚至可能因忽视安全建设&a…

(八)centos7案例实战——docker仓库Harbor服务安装部署

前言 Harbor &#xff08;港口&#xff0c;港湾&#xff09;是一个用于存储和分发Docker镜像的企业级Registry服务器。我们可以使用dockerhub仓库或者阿里云docker仓库等第三方仓库管理我们的docker镜像。对于企业来说&#xff0c;条件允许&#xff0c;可以搭建自己的docker镜…

FEDformer 代码分析(1)

参数设置如下&#xff0c; --seq_len 是 96 --label_len 是 48 --pred_len 是 96 也就是说&#xff0c;输入是96的&#xff0c;预测96. batch_x 是 &#xff08;1,96,7&#xff09;的维度的。 batch_x_mark 是&#xff08;1,96,4&#xff09;的维度的。 batch_y的维度是…

嵌入式系统开发笔记107:层次化软件设计思想

文章目录前言一、嵌入式系统设计的本质二、基于寄存器结构的程序设计三、嵌入式系统优良程序的评判标准四、计算机上的软件分层五、嵌入式程序的分层设计前言 本文以思维导图的形式介绍层次化软件设计思想。 一、嵌入式系统设计的本质 二、基于寄存器结构的程序设计 三、嵌入式…

Java 内存溢出(一)原因、复现、排查

目录一、内存溢出原因二、内存溢出实例1、堆溢出2.虚拟机栈和本地方法栈溢出3.方法区和运行时常量池溢出4.本机直接内存溢出三、内存溢出排查内存溢出&#xff1a; 是指应用系统中存在无法回收的内存或使用的内存过多&#xff0c;最终使得程序运行要用到的内存大于虚拟机能提供…

[附源码]计算机毕业设计JAVA基于新高考模式下的排课系统

[附源码]计算机毕业设计JAVA基于新高考模式下的排课系统 项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; S…

强化学习论文分析5---多基站_强化学习_联邦学习_计算卸载

目录一、文章概述二、理论模型1.系统目标2.约束条件3.公式推导(1)任务量(2)卸载率(3)本地能耗(4)传输能耗(5)MEC计算能耗(6)总述三、算法架构----多基站联合强化学习1.网络结构图2.算法总述3.Actor网络(1).输入状态(2).输出动作4.Critic网络(1).环境奖励5.伪代码四、算法架构--…

信号线多长算长呢——之上升沿与时延的爱恨情仇

忆往昔岁月&#xff0c;看着PCB上弯弯曲曲的走线&#xff0c;看着书中所说的端接&#xff0c;想象着日后自己也可以这么牛逼&#xff0c;能够设计出这么复杂的电路。“过来焊板子啦”一句话又将我拉回了现实&#xff0c;哎&#xff0c;过来吸一会我们硬件攻城狮的精神鸦片——松…

实验四 软中断信号及处理

1.利用sleep、pause、alarm函数设定闹钟&#xff0c;定时显示信息。 #include<unistd.h> #include<stdio.h> #include<stdlib.h> #include<signal.h> int main(){int ret;alarm(50);sleep(30);retalarm(10);printf("%d\n",ret);pause();pri…

C++11

1. C11简介 相比于 C98/03&#xff0c;C11则带来了数量可观的变化&#xff0c;其中包含了约140个新特性&#xff0c;以及C03标准中约600个缺陷的修正&#xff0c;这使得C11更像是从C98/03中孕育出的一种新语言。相比较而言&#xff0c;C11能更好地用于系统开发和库开发、语法更…

玩机搞机---脱离电脑 用手机给手机刷机 解锁bl 获取root的方法教程

友友们有时候手机出问题需要刷机而手头缺没有电脑的情况下该如何解决呢&#xff0c;今天的话题就聊聊 这方面的常识。其实类似手机给手机刷机的方法有很多&#xff0c;但原理都是一样的&#xff0c;有时候可以起到应急解决方法&#xff0c; 一 需要的工具与准备工作; 手机A …

长尾词挖掘免费工具-长尾关键词挖掘词

什么是关键词&#xff1f;在 SEO&#xff0c;搜索引擎优化的范畴里&#xff0c;关键词指的是用户输入到搜索框内的那一个&#xff0c;或者几个词&#xff0c;目的是为了找到他要的答案。搜索引擎收到用户发送的这几个词&#xff0c;或者说关键词后&#xff0c;就会试图找到最合…

同惠TH9310耐压测试仪应用举例

TH9310交直流耐压绝缘测试仪是一款小功率经济型智能安规测试仪器。体积小、重量轻、外形美观、操作简便。TH9320产品可广泛应用于家用电器、变压器、电气设备、元器件的安全性能检查。 应用举例&#xff1a; ■ 自动化测试系统 ■ 家用电器 ■ 变压器、电机 ■ 电气设备 …