在 React 中使用 he-tree-react 构建拖拽树视图

发布: (2026年1月20日 GMT+8 02:40)
9 min read
原文: Dev.to

Source: Dev.to

he‑tree‑react 是一个强大的 React 库,用于构建具有拖拽、排序和灵活数据操作的树组件。它提供直观的 API,帮助创建交互式层级结构,用户可以重新排序节点、在分支之间移动项目并组织数据。

前置条件

  • Node.js ≥ 14.0
  • npm, yarn, 或 pnpm
  • 一个 React 项目(React ≥ 16.8)——例如使用 create‑react‑app 创建的项目
  • 对 React Hook(useStateuseEffect)的基本了解
  • 熟悉 JavaScript/TypeScript
  • 理解树形数据结构和拖拽概念

安装

# npm
npm install he-tree-react

# yarn
yarn add he-tree-react

# pnpm
pnpm add he-tree-react

安装完成后,您的 package.json 应该包含类似以下内容:

{
  "dependencies": {
    "he-tree-react": "^2.0.0",
    "react": "^18.0.0",
    "react-dom": "^18.0.0"
  }
}

基础拖拽树

创建一个简单的树组件。

src/TreeExample.jsx

import React, { useState } from 'react';
import { Tree } from 'he-tree-react';

const initialData = [
  {
    id: 1,
    text: 'Item 1',
    children: [
      { id: 2, text: 'Child 1' },
      { id: 3, text: 'Child 2' }
    ]
  },
  {
    id: 4,
    text: 'Item 2',
    children: [{ id: 5, text: 'Child 3' }]
  },
  { id: 6, text: 'Item 3' }
];

function TreeExample() {
  const [data, setData] = useState(initialData);

  return (
    <Tree
      data={data}
      draggable
      droppable
      onChange={setData}
    />
  );
}

export default TreeExample;

src/App.jsx

import React from 'react';
import TreeExample from './TreeExample';
import './App.css';

function App() {
  return (
    <div className="App">
      <TreeExample />
    </div>
  );
}

export default App;

运行应用后,现在会显示一个带有完整拖拽支持的基础树。

核心概念

概念描述
Tree component主组件 (<Tree />) 用于渲染层级结构。
Node structure每个节点必须包含 idtext,并可选地包含 children 数组。
Drag & drop通过 draggabledroppable 属性启用。
Change handling使用 onChange 在移动后获取更新后的树数据。
Nested levels该库支持无限层级深度。
State management将树数据保存在组件状态中,并通过 onChange 更新。

高级示例 – 文件资源管理器

src/AdvancedTreeExample.jsx

import React, { useState } from 'react';
import { Tree } from 'he-tree-react';

const advancedData = [
  {
    id: 1,
    text: 'Documents',
    children: [
      { id: 2, text: 'Project 1' },
      { id: 3, text: 'Project 2' }
    ]
  },
  {
    id: 4,
    text: 'Images',
    children: [
      { id: 5, text: 'Vacation' },
      { id: 6, text: 'Family' }
    ]
  },
  { id: 7, text: 'Downloads' }
];

function AdvancedTreeExample() {
  const [data, setData] = useState(advancedData);
  const [selectedNode, setSelectedNode] = useState(null);

  const handleNodeClick = (node) => {
    setSelectedNode(node);
    console.log('Selected node:', node);
  };

  return (
    <div className="advanced-example">
      {/* Tree panel */}
      <section>
        <h3>File Tree</h3>
        <Tree
          data={data}
          draggable
          droppable
          onChange={setData}
          onNodeClick={handleNodeClick}
        />
      </section>

      {/* Details panel */}
      <section>
        <h3>Selected Node</h3>
        {selectedNode ? (
          <div>
            <p><strong>Text:</strong> {selectedNode.text}</p>
            <p><strong>ID:</strong> {selectedNode.id}</p>
            <p><strong>Has Children:</strong> {selectedNode.children ? 'Yes' : 'No'}</p>
          </div>
        ) : (
          <p>No node selected</p>
        )}
      </section>
    </div>
  );
}

export default AdvancedTreeExample;

此示例演示:

  • 多层嵌套
  • 节点选择处理(onNodeClick
  • 显示所选节点的详细信息

实际案例 – 任务组织器

src/TaskOrganizer.jsx

import React, { useState } from 'react';
import { Tree } from 'he-tree-react';

const initialTasks = [
  {
    id: 1,
    text: '📋 Project Planning',
    children: [
      { id: 2, text: '✅ Define requirements' },
      { id: 3, text: '⏳ Create timeline' },
      { id: 4, text: '📝 Write proposal' }
    ]
  },
  {
    id: 5,
    text: '💻 Development',
    children: [
      { id: 6, text: '✅ Setup project' },
      { id: 7, text: '⏳ Implement features' },
      { id: 8, text: '📝 Write tests' }
    ]
  },
  {
    id: 9,
    text: '🚀 Deployment',
    children: [{ id: 10, text: '📝 Prepare release' }]
  }
];

function TaskOrganizer() {
  const [tasks, setTasks] = useState(initialTasks);

  const handleChange = (newData) => {
    setTasks(newData);
    console.log('Tasks updated:', newData);
  };

  return (
    <div className="task-organizer">
      <h3>Task Organizer</h3>
      <p>Drag and drop tasks to reorganize them</p>
      <Tree
        data={tasks}
        draggable
        droppable
        onChange={handleChange}
      />
    </div>
  );
}

export default TaskOrganizer;

使用此组件让用户重新排序任务,在类别之间移动子任务,并保持层级结构的最新状态。

功能概述

  • Tree – 主组件,内置拖拽功能。
  • Node schemaidtext,可选 children
  • Props
    • data – 树数据数组。
    • onChange – 在移动后接收更新后树的回调函数。
    • draggable / droppable – 启用拖拽/放置。
    • onNodeClick – 可选的节点点击处理函数,用于节点选择。
  • State handling – 将树数据保存在 React 状态中,并通过 onChange 更新。
  • Nested structures – 开箱即支持无限深度。

下一步

  1. 添加自定义节点渲染 – 使用 renderNode 属性(如果可用)来显示图标、复选框等。
  2. 持久化更改 – 在 onChange 中通过 API 调用将更新后的树发送到后端。
  3. 样式 – 使用 CSS 模块或 styled‑components 覆盖默认样式,以获得精致的 UI。

祝您使用 he‑tree‑react 编码愉快!

文件管理器组件

// src/FileManager.jsx
import React, { useState } from 'react';
import { Tree } from 'he-tree-react';

const initialFiles = [
  {
    id: 1,
    text: '📁 Documents',
    children: [
      { id: 2, text: '📄 report.pdf' },
      { id: 3, text: '📄 presentation.pptx' }
    ]
  },
  {
    id: 4,
    text: '📁 Images',
    children: [
      { id: 5, text: '🖼️ photo1.jpg' },
      { id: 6, text: '🖼️ photo2.png' }
    ]
  },
  { id: 7, text: '📄 readme.txt' }
];

function FileManager() {
  const [files, setFiles] = useState(initialFiles);

  return (
    <div className="file-manager">
      <h3>File Manager</h3>
      <p>Drag files and folders to reorganize</p>
      <Tree
        data={files}
        draggable
        droppable
        onChange={setFiles}
      />
    </div>
  );
}

export default FileManager;

应用集成

// src/App.jsx
import React from 'react';
import TaskOrganizer from './TaskOrganizer';
import FileManager from './FileManager';
import './App.css';

function App() {
  return (
    <div className="App">
      <TaskOrganizer />
      <FileManager />
    </div>
  );
}

export default App;

本示例演示的内容

  • 任务组织器界面
  • 拖拽功能
  • 带节点重新组织的文件管理器
  • 通过 React Hook 进行状态管理
  • 交互式树结构

故障排除

问题可能原因解决方案
树未渲染数据结构不正确确保每个节点都有 id text 属性;根数据必须是数组。
拖拽功能不可用属性未设置确认 draggabledroppabletrue。检查浏览器控制台是否有错误。
状态未更新缺少 onChange 处理函数提供一个更新状态的 onChange 属性(例如 setFiles)。如有需要,请使用函数式更新。
节点未移动ID 重复每个节点都需要唯一的 id。确认 onChange 正确返回新的树数据。
样式问题CSS 冲突he-tree-react 自带默认样式。可以使用自定义 CSS 覆盖,但请确保全局样式没有覆盖组件的类。
大树的性能问题渲染次数过多考虑对树进行虚拟化或限制初始深度。对耗时的节点渲染器使用 React.memo

下一步

现在您已经了解了 he‑tree‑react 的基础,可以探索更高级的功能:

  • 自定义节点渲染
  • 拖拽约束(例如,仅允许特定节点被放下)
  • 树内搜索和过滤
  • 节点操作的上下文菜单
  • 自定义拖拽手柄
  • 与外部状态管理库集成(Redux、Zustand 等)

查看官方仓库获取更多细节:
🔗

Summary

您已成功在 React 应用中设置 he‑tree‑react,创建了拖拽‑与‑放置树视图,并学习了如何管理其状态。该库提供了强大且灵活的解决方案,用于在 React 中构建交互式层次数据展示。

Keywords

  • he-tree-react
  • he-tree-react 拖放
  • React 拖放树
  • he-tree-react 安装
  • React 树组件
  • he-tree-react 教程
  • React 分层数据
  • he-tree-react 示例
  • React 可排序树
  • he-tree-react 设置
  • React 树视图库
  • he-tree-react 入门
  • React 交互式树
  • he-tree-react 高级用法
Back to Blog

相关文章

阅读更多 »

React 编码挑战:卡片翻转游戏

React 卡片翻转游戏 – 代码 tsx import './styles.css'; import React, { useState, useEffect } from 'react'; const values = 1, 2, 3, 4, 5; type Card = { id: numb...