You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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>
  );
}

实现效果说明

改造后的逻辑完全匹配需求:

  1. 点击父级复选框时,所有子级复选框同步切换选中/未选中状态
  2. 子级复选框状态变化时,若同层级子项未全部选中/未选中,父级自动进入半选状态
  3. 所有子级全部选中时父级自动同步为选中状态,所有子级全部未选中时父级自动同步为未选中状态

内容的提问来源于stack exchange,提问作者Wendell

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.28 01:06:09