react实现tree check
React 实现 Tree Check 功能
在 React 中实现树形结构的复选框(Tree Check)功能通常涉及递归渲染节点、管理选中状态以及处理父子节点的联动逻辑。以下是具体实现方法:
数据结构设计
树形结构的数据通常以嵌套对象形式表示,每个节点包含 id、label、children 等属性。例如:
const treeData = [
{
id: '1',
label: 'Parent 1',
children: [
{ id: '1-1', label: 'Child 1-1' },
{ id: '1-2', label: 'Child 1-2' },
],
},
];
状态管理
使用 React 的 useState 或 useReducer 管理选中状态。可以存储选中节点的 id 或完整路径:
const [checkedKeys, setCheckedKeys] = useState(new Set());
递归渲染树节点
通过递归组件渲染树形结构,并为每个节点添加复选框:
const TreeNode = ({ node, checkedKeys, onCheck }) => {
const isChecked = checkedKeys.has(node.id);
return (
<div>
<label>
<input
type="checkbox"
checked={isChecked}
onChange={() => onCheck(node.id, !isChecked)}
/>
{node.label}
</label>
{node.children && (
<div style={{ marginLeft: '20px' }}>
{node.children.map(child => (
<TreeNode
key={child.id}
node={child}
checkedKeys={checkedKeys}
onCheck={onCheck}
/>
))}
</div>
)}
</div>
);
};
处理选中逻辑
实现父子节点联动的核心逻辑:
- 选中父节点时自动选中所有子节点
- 取消父节点时自动取消所有子节点
- 部分选中子节点时父节点显示为半选状态
const updateCheckedKeys = (id, isChecked) => {
const newCheckedKeys = new Set(checkedKeys);
// 递归处理子节点
const toggleChildren = (node) => {
if (node.id === id) isChecked ? newCheckedKeys.add(id) : newCheckedKeys.delete(id);
if (node.children) node.children.forEach(toggleChildren);
};
// 查找目标节点并更新
const traverseTree = (nodes) => {
nodes.forEach(node => {
if (node.id === id || newCheckedKeys.has(id)) {
toggleChildren(node);
}
if (node.children) traverseTree(node.children);
});
};
traverseTree(treeData);
setCheckedKeys(newCheckedKeys);
};
半选状态实现
通过计算子节点的选中状态决定父节点是否显示半选:
const isIndeterminate = (node) => {
if (!node.children) return false;
const childChecked = node.children.some(child => checkedKeys.has(child.id));
const allChecked = node.children.every(child => checkedKeys.has(child.id));
return childChecked && !allChecked;
};
在复选框属性中添加 indeterminate:
<input
type="checkbox"
checked={isChecked}
indeterminate={isIndeterminate(node)}
onChange={() => onCheck(node.id, !isChecked)}
/>
完整示例代码
import React, { useState } from 'react';
const TreeCheck = ({ data }) => {
const [checkedKeys, setCheckedKeys] = useState(new Set());
const updateCheckedKeys = (id, isChecked) => {
const newCheckedKeys = new Set(checkedKeys);
const toggleChildren = (node) => {
if (node.id === id) isChecked ? newCheckedKeys.add(id) : newCheckedKeys.delete(id);
if (node.children) node.children.forEach(toggleChildren);
};
const traverseTree = (nodes) => {
nodes.forEach(node => {
if (node.id === id || newCheckedKeys.has(id)) toggleChildren(node);
if (node.children) traverseTree(node.children);
});
};
traverseTree(data);
setCheckedKeys(newCheckedKeys);
};
const isIndeterminate = (node) => {
if (!node.children) return false;
const childChecked = node.children.some(child => checkedKeys.has(child.id));
const allChecked = node.children.every(child => checkedKeys.has(child.id));
return childChecked && !allChecked;
};
const TreeNode = ({ node }) => {
const isChecked = checkedKeys.has(node.id);
return (
<div>
<label>
<input
type="checkbox"
checked={isChecked}
indeterminate={isIndeterminate(node)}
onChange={() => updateCheckedKeys(node.id, !isChecked)}
/>
{node.label}
</label>
{node.children && (
<div style={{ marginLeft: '20px' }}>
{node.children.map(child => (
<TreeNode key={child.id} node={child} />
))}
</div>
)}
</div>
);
};
return <div>{data.map(node => <TreeNode key={node.id} node={node} />)}</div>;
};
第三方库推荐
若需快速实现复杂功能,可考虑以下库:
- react-checkbox-tree:专为树形复选框设计的组件。
- rc-tree:Ant Design 的底层树组件,支持复选框。
- downshift:灵活的可定制组件,适用于树形选择。
以上方法可根据实际需求调整,例如优化性能(如避免递归渲染)或添加异步加载子节点功能。







