React探索高性能Tree树组件实现——react-window、react-vtree

🚀 简介

在现代 Web 应用中,处理大量层级数据的树形结构是一个常见挑战。传统的树组件在面对成千上万个节点时往往会出现性能瓶颈,导致页面卡顿、内存占用过高等问题。本文将深入探讨如何使用 react-window 和 react-vtree 构建高性能的虚拟化树组件,实现流畅的用户体验。react-virtualized-auto-sizer 用于自动调整容器大小。

🎯 核心优势

  • 🔥 极致性能:虚拟化渲染,只渲染可视区域内的节点
  • 💾 内存优化:显著降低 DOM 节点数量,减少内存占用
  • ⚡ 流畅体验:支持大数据量(10 万+节点)的流畅滚动
  • 🎨 高度定制:灵活的样式和交互定制能力
  • 📱 响应式:完美适配各种屏幕尺寸

🛠️ 技术实现原理

虚拟化核心概念

虚拟化技术的核心思想是按需渲染

  • 只渲染用户当前可见的树节点
  • 动态计算节点位置和高度
  • 智能预加载即将进入视口的节点
  • 及时回收离开视口的节点

技术栈选择

  • react-window –> 基础虚拟化能力
  • react-vtree –> 树形结构专用
  • Tailwind CSS –> 现代化样式

📦 安装依赖

# 核心依赖
npm install react-window react-vtree# 样式和工具
npm install tailwindcss @types/react-window# 可选:自动调整容器大小
npm install react-virtualized-auto-sizer

🎨 基础实现示例

简单树形结构

import React, { useMemo } from "react";
import { FixedSizeList as List } from "react-window";
import AutoSizer from "react-virtualized-auto-sizer";const SimpleTree = () => {// 模拟树形数据const treeData = useMemo(() => {const generateNode = (id, level = 0, maxLevel = 4) => ({id,name: `节点 ${id}`,level,children:level < maxLevel? Array.from({ length: Math.floor(Math.random() * 5) + 1 }, (_, i) =>generateNode(`${id}-${i}`, level + 1, maxLevel)): [],});return Array.from({ length: 10 }, (_, i) => generateNode(i.toString()));}, []);// 扁平化树数据const flattenTree = (nodes, openNodes = new Set()) => {const result = [];const traverse = (node, depth = 0) => {result.push({ ...node, depth, isOpen: openNodes.has(node.id) });if (openNodes.has(node.id) && node.children?.length > 0) {node.children.forEach((child) => traverse(child, depth + 1));}};nodes.forEach((node) => traverse(node));return result;};const [openNodes, setOpenNodes] = React.useState(new Set(["0", "1"]));const flatData = useMemo(() => flattenTree(treeData, openNodes),[treeData, openNodes]);const toggleNode = (nodeId) => {setOpenNodes((prev) => {const newSet = new Set(prev);if (newSet.has(nodeId)) {newSet.delete(nodeId);} else {newSet.add(nodeId);}return newSet;});};const Node = ({ index, style }) => {const node = flatData[index];// Add safety check for undefined nodeif (!node) {return <div style={style}>Loading...</div>;}const hasChildren = node.children && node.children.length > 0;return (<divstyle={style}className={`flex items-center px-4 py-2 border-b border-gray-100 hover:bg-gray-50 transition-colors ${index % 2 === 0 ? "bg-white" : "bg-gray-25"}`}><divclassName="flex items-center"style={{ paddingLeft: `${node.depth * 24}px` }}>{hasChildren && (<buttononClick={() => toggleNode(node.id)}className={`w-6 h-6 mr-2 flex items-center justify-center rounded hover:bg-gray-200 transition-colors ${node.isOpen ? "text-blue-600" : "text-gray-400"}`}><svgclassName={`w-4 h-4 transform transition-transform ${node.isOpen ? "rotate-90" : ""}`}fill="currentColor"viewBox="0 0 20 20"><pathfillRule="evenodd"d="M7.293 14.707a1 1 0 010-1.414L10.586 10 7.293 6.707a1 1 0 011.414-1.414l4 4a1 1 0 010 1.414l-4 4a1 1 0 01-1.414 0z"clipRule="evenodd"/></svg></button>)}<div className="flex items-center"><divclassName={`w-6 h-6 rounded-full mr-3 flex items-center justify-center text-white text-xs font-medium ${hasChildren ? "bg-blue-500" : "bg-gray-400"}`}>{hasChildren ? "📁" : "📄"}</div><span className="text-gray-700 font-medium">{node.name}</span><span className="ml-2 text-xs text-gray-400">ID: {node.id}</span></div></div></div>);};return (<div className="w-full h-screen border border-gray-200 rounded-lg overflow-hidden shadow-lg flex flex-col"><div className="bg-gradient-to-r from-blue-600 to-indigo-600 text-white p-4 flex-shrink-0"><h3 className="text-lg font-semibold">高性能虚拟化树组件</h3><p className="text-blue-100 text-sm">支持大数据量,流畅滚动体验</p></div><div className="flex-1"><AutoSizer>{({ height, width }) => (<ListitemCount={flatData.length}itemSize={50}height={height}width={width}className="scrollbar-thin scrollbar-thumb-blue-300 scrollbar-track-blue-50">{Node}</List>)}</AutoSizer></div></div>);
};export default SimpleTree;

🎯 性能优化策略与实现

  • 虚拟化渲染: 通过 react-window 的 FixedSizeList 组件实现虚拟滚动,只渲染可视区域内的节点
<ListitemCount={flatData.length}itemSize={50}height={height}width={width}className="scrollbar-thin scrollbar-thumb-blue-300 scrollbar-track-blue-50"
>{Node}
</List>
  • DOM 节点复用: 通过 key 属性确保 DOM 节点的有效复用,减少创建和销毁操作
const Node = ({ index, style }) => {const node = flatData[index];// ... 节点渲染逻辑
};
  • 状态管理优化: 使用 useMemo 缓存计算结果,避免不必要的重复计算
const flatData = useMemo(() => flattenTree(treeData, openNodes),[treeData, openNodes]
);
  • 及时清理: 组件卸载时及时清理事件监听器和定时器
useEffect(() => {return () => {// 清理工作};
}, []);

🎉 总结

通过 react-window 和 react-vtree 的结合使用,我们成功构建了一个高性能的虚拟化树组件,实现了:

  • ✅ 极致性能:支持 10 万+节点的流畅渲染
  • ✅ 内存优化:显著降低 DOM 节点数量和内存占用
  • ✅ 用户体验:流畅的滚动和交互体验
  • ✅ 可维护性:清晰的代码结构和组件设计
  • ✅ 可扩展性:灵活的配置和自定义能力

这种技术方案不仅解决了大数据量树形结构的性能问题,还为复杂的企业级应用提供了可靠的技术基础。随着 Web 技术的不断发展,虚拟化技术将在更多场景中发挥重要作用。

 React探索高性能Tree树组件实现——react-window、react-vtree - 高质量源码分享平台-免费下载各类网站源码与模板及前沿技术分享

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

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

相关文章

C++ 中的默认构造函数:非必要,不提供

《More Effective C&#xff1a;35个改善编程与设计的有效方法》 读书笔记&#xff1a;非必要不提供default constructor在 C 中&#xff0c;默认构造函数&#xff08;即无需任何参数即可调用的构造函数&#xff09;是对象“无中生有”的一种方式。它的核心作用是在没有外部信息…

如何选择低代码开发平台

选择低代码开发平台需要考虑平台的开发效率、灵活性和扩展能力、安全性和合规性、成本效益等关键因素。 具体来说&#xff0c;平台的灵活性和扩展能力尤为重要&#xff0c;这决定了平台是否能长期满足企业日益增长的复杂需求。例如&#xff0c;企业在评估平台时&#xff0c;应关…

电子数据取证领域的双轮驱动——手工分析 vs 自动化分析

在你刚步入电子数据取证领域时&#xff0c;可能很快就注意到一个普遍现象&#xff1a;大多数取证分析师前期都花费大量时间在网上查阅博客、PDF、推文等信息&#xff0c;寻找证据线索的“藏身之处”——例如注册表项、日志文件路径、可疑文件命名模式或远程登录痕迹等。这种信息…

《Python 实时通信全解:掌握 WebSocket 技术与 HTTP 的本质区别》

🚀《Python 实时通信全解:掌握 WebSocket 技术与 HTTP 的本质区别》 引言:通信方式的演进与 Python 的角色 在数字化世界里,**“实时性”**已经成为构建高质量应用的核心诉求。从聊天工具到股票交易系统,再到物联网设备管理——通信的即时响应能力直接决定用户体验。而…

GeoTools 自定义坐标系

前言在GIS开发中&#xff0c;坐标系统是重中之重&#xff0c;在接到任务时首先要确定的就是坐标系。大多数地图库或者互联网地图默认支持WGS84地理坐标系和Web墨卡托投影坐标系。而在我国要求使用自然资源数据使用2000国家大地坐标&#xff08;CGCS2000&#xff09;。1. 背景 经…

[特殊字符] Java反射从入门到飞升:手撕类结构,动态解析一切![特殊字符]

【&#x1f50d;震撼揭秘】 你是否曾想窥探Java类的内部结构&#xff1f;&#x1f914; 是否好奇Spring框架如何实现"万物皆可注入"&#xff1f;✨ 本文将带你从反射小白晋升为反射高手&#xff0c;用一行代码透视任意类的构造方法、成员变量和私有方法&#xff01;&…

CMake与catkin_make的find_package()命令使用说明

在 CMake 中&#xff0c;find_package() 是一个核心函数&#xff0c;用于查找并加载外部依赖库的配置。它的主要作用是定位头文件、库文件&#xff0c;并设置相关变量&#xff0c;以便后续编译和链接。以下是详细解析&#xff1a; 1. 基本语法 find_package(<PackageName&g…

Spring--BeanFactoryPostProcessor的用法

原文网址&#xff1a;Spring--BeanFactoryPostProcessor的用法_IT利刃出鞘的博客-CSDN博客 简介 说明 本文介绍Spring的BeanFactoryPostProcessor的用法。 BeanPostProcessor和BeanFactoryPostProcessor的区别 项BeanPostProcessorBeanFactoryPostProcessor处理的对象处理…

了解类加载器吗?类加载器的类型有哪些?

一、什么是类加载器&#xff08;ClassLoader&#xff09; 类加载器是 Java 虚拟机中的一部分&#xff0c;负责将 .class 文件加载到 JVM 内存中&#xff0c;生成对应的 Class 对象。 Java 程序中所有的类在使用前都必须通过类加载器加载进 JVM&#xff0c;才能被执行。二、类加…

PHP面向对象高级特性:魔术方法、对象迭代器与设计模式应用

引言 在前一篇文章中,我们探讨了PHP的Traits、匿名类和对象比较机制。本文将深入PHP面向对象编程的更多高级特性,包括魔术方法、对象迭代器以及常用设计模式的实际应用,这些特性能够帮助开发者构建更加灵活和强大的面向对象系统。 魔术方法深度解析 魔术方法是PHP中一组以…

【Java基础】一个月教你轻松掌握Java——第三篇Git

一、Java概述&#xff08;之前的文章&#xff09;二、版本控制工具Git其实这个与Java基础关系不大&#xff0c;但是这个工具还是很重要的&#xff0c;不管是团队之间打比赛还是就业都应该学会它&#xff0c;秉持着学的早一些&#xff0c;用的时间长一点&#xff0c;会更熟练。&…

【C# in .NET】16. 探秘类成员-索引器:通过索引访问对象

探秘类成员-索引器:通过索引访问对象 在 C# 中,索引器(Indexer)是一种独特的类成员,它允许类或结构的实例像数组一样被索引访问,为数据访问提供了极大的灵活性。本文将从基础概念出发,深入.NET 框架底层,剖析索引器的实现机制,并通过实战案例展示其强大的应用价值。 …

idea出现:java: Target level ‘1.7‘ is incompatible with source level ‘1.8‘.解决办法

在文件->设置->java编译器&#xff0c;把这里版本对应上。这里用的是8版本

ssms(SQL 查询编辑器) 添加快捷键 Ctrl+D(功能等于Ctrl+C + Ctrl+V),一步到位

1,打开ssms 工具&#xff0c;打开对应添加快捷键得地方2&#xff0c;分配 快捷键3&#xff0c;看效果

数学建模--层次分析法

层次分析法&#xff08;AHP&#xff09;笔记 一、核心概念 &#xff08;一&#xff09;问题本质 面对多方案、多准则决策&#xff0c;将复杂问题分层拆解&#xff0c;通过定性与定量结合&#xff0c;确定各因素权重&#xff0c;选出最优方案&#xff0c;比如选“微博之星”时综…

人工智能教研室暑期培训flask全栈开发培训

人工智能教研室暑期培训flask全栈开发培训第一天&#xff1a;Flask 基础入门与环境搭建实践项目&#xff1a;搭建个人博客首页&#xff0c;包含文章列表与详情页上午&#xff1a;环境搭建与 Flask 基础1. 安装 Python 与虚拟环境配置2. Flask 框架简介与第一个 "Hello Wor…

MySQL(141)如何处理重复数据问题?

处理重复数据问题是数据管理中的一个常见挑战。重复数据会影响数据库的性能、占用资源&#xff0c;并且可能导致数据分析结果的偏差。以下是处理重复数据问题的详细步骤以及结合代码的示例。 一、识别重复数据 首先&#xff0c;需要识别数据库中的重复数据。可以使用 SQL 查询来…

MySQL 核心知识点梳理(3)

目录 SQL优化 23什么是慢SQL 如何优化呢? 如何利于覆盖索引 如何使用联合索引 如何进行分页优化 Join代替子查询 为什么要小表驱动大表? 为什么避免join太多的表? 如何进行排序优化 什么是filesort 全字段排序和rowid排序 条件下推 索引 索引为什么能提高MyS…

关于注册登录功能制作的步骤(文件IO存储+LVGL弹窗提示)

按你的需求&#xff08;文件IO存储LVGL弹窗提示&#xff09;&#xff0c;工程需创建以下文件&#xff0c;代码按功能模块化存放&#xff0c;清晰明了&#xff1a;一、需要创建的文件清单 文件名 作用 存放内容 main.c 程序入口 主函数、硬件初始化、LVGL初始化、启动界面 ui.…

自媒体端后台设计指南:从注册认证到内容管理的全流程搭建

自媒体端后台设计指南&#xff1a;从注册认证到内容管理的全流程搭建自媒体端后台是专业创作者管理内容、粉丝和数据的核心阵地&#xff0c;其设计直接影响创作效率和平台运营质量。一个功能清晰、操作便捷的后台系统&#xff0c;能让创作者专注于内容生产&#xff0c;而非被复…