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
英文地址,請注明出處:http://en.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;而非被復…