React多层级嵌套复选框父子联动及半选状态功能实现求助
你现有代码的核心问题是每个CheckboxItem的选中状态独立保存在组件内部,父子组件没有状态联动通道,无法实现嵌套交互。你需要将选中状态提升到上层统一管理,再增加父子状态联动逻辑即可实现需求,完整改造方案如下:
步骤1:预处理JSON数据
给每个节点新增唯一id字段用于状态追踪,示例结构:
{ "itens": [ { "id": "1", "name": "父级分类1", "children": { "1-1": {"id": "1-1", "name": "子分类1-1", "children": {}}, "1-2": {"id": "1-2", "name": "子分类1-2", "children": {"1-2-1": {"id": "1-2-1", "name": "三级分类1-2-1", "children": {}}}} } } ] }
步骤2:改造主入口文件,统一管理全局状态
import React, { useState, useCallback } from "react"; import ReactDOM from "react-dom"; import { ChildrenMap } from "./components/ChildrenMap"; import data from "./data.json"; // 递归获取指定节点所有后代节点id const getAllDescendantIds = (node) => { let ids = []; const children = Object.values(node.children || {}); children.forEach(child => { ids.push(child.id); ids = ids.concat(getAllDescendantIds(child)); }) return ids; } // 递归计算父节点的选中/半选状态 const calcParentState = (parentNode, checkedMap) => { const children = Object.values(parentNode.children || {}); if (children.length === 0) return checkedMap[parentNode.id] || false; const childStates = children.map(child => calcParentState(child, checkedMap)); const allChecked = childStates.every(state => state === true); const allUnchecked = childStates.every(state => state === false); if (allChecked) return true; if (allUnchecked) return false; return 'indeterminate'; } // 递归查找指定id的父节点 const findParentNode = (root, targetId) => { const children = Object.values(root.children || {}); for (let child of children) { if (child.id === targetId) return root; const found = findParentNode(child, targetId); if (found) return found; } return null; } function App() { // 全局存储所有节点的状态:true=选中 / false=未选中 / 'indeterminate'=半选 const [checkedMap, setCheckedMap] = useState({}); const handleCheck = useCallback((node, newChecked) => { setCheckedMap(prev => { const newMap = {...prev}; // 更新当前节点状态 newMap[node.id] = newChecked; // 同步更新所有后代节点状态 const descendantIds = getAllDescendantIds(node); descendantIds.forEach(id => newMap[id] = newChecked); // 向上递归更新所有祖先节点状态 let parent = findParentNode(data, node.id); while(parent) { newMap[parent.id] = calcParentState(parent, newMap); parent = findParentNode(data, parent.id); } return newMap; }) }, [data]) return ( <> {data.itens.map((item) => ( <div key={item.id}> <ChildrenMap itens={item} onCheck={handleCheck} checkedMap={checkedMap} /> </div> ))} </> ); }
步骤3:改造CheckboxItem为受控组件
import Checkbox from "react-three-state-checkbox"; export function CheckboxItem(props) { const isChecked = props.checked === true; const isIndeterminate = props.checked === 'indeterminate'; function clickCheckbox() { props.onChange(!isChecked); } return ( <> <Checkbox checked={isChecked} indeterminate={isIndeterminate} onChange={clickCheckbox} /> {props.children} </> ); }
步骤4:改造ChildrenMap组件透传参数
import { CheckboxItem } from "../CheckboxItem"; import * as S from "./styled"; export function ChildrenMap({ itens, onCheck, checkedMap }) { const filhos = Object.values(itens); return ( <div> {filhos.map((item) => ( <S.Itens key={item.id}> <CheckboxItem checked={checkedMap[item.id] || false} onChange={(newVal) => onCheck(item, newVal)} > {item.name} </CheckboxItem> {Object.keys(item.children || {}).length > 0 && ( <ChildrenMap itens={item.children} onCheck={onCheck} checkedMap={checkedMap} /> )} </S.Itens> ))} </div> ); }
实现效果说明
改造后的逻辑完全匹配需求:
- 点击父级复选框时,所有子级复选框同步切换选中/未选中状态
- 子级复选框状态变化时,若同层级子项未全部选中/未选中,父级自动进入半选状态
- 所有子级全部选中时父级自动同步为选中状态,所有子级全部未选中时父级自动同步为未选中状态
内容的提问来源于stack exchange,提问作者Wendell
相关产品推荐
相关产品推荐

