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

ReactJS:如何通过Checkbox更新数组中指定元素的状态

解决嵌套数组中Checkbox点击仅更新对应元素状态的问题

问题分析

你的代码存在几个关键问题导致无法正确更新单个Checkbox状态:

  1. 未传递元素标识:点击Checkbox时没有传入当前元素的唯一标识(如codigo或id),无法定位要修改的元素。
  2. 直接修改状态数组:直接修改arrayGrupoNiveis中的元素属性,没有通过setArrayGrupoNiveis创建新数组触发React重新渲染。
  3. 逻辑判断错误:e.target是DOM元素,和数值类型的codigo直接比较永远不相等,导致找不到目标元素。

解决方案

1. 传递元素标识到处理函数

在渲染Checkbox时,通过onClick传入当前子元素的codigo(或id),明确指定点击的目标元素:

<Checkbox
  checked={filho.marcado}
  size="small"
  onClick={() => handleCheckBox(filho.codigo)}
/>

2. 深拷贝状态数组并修改目标元素

React状态不可直接修改,需要创建原数组的深拷贝,找到对应元素后切换其marcado状态,再通过setArrayGrupoNiveis更新状态:

const handleCheckBox = (targetCodigo: number) => {
  // 深拷贝原数组,避免直接修改状态
  const updatedArray = JSON.parse(JSON.stringify(arrayGrupoNiveis));
  
  // 遍历外层数组,找到包含目标子元素的父项
  updatedArray.forEach(nivelItem => {
    if (nivelItem.filhos) {
      // 遍历子元素,找到目标元素并切换marcado状态
      nivelItem.filhos.forEach(filho => {
        if (filho.codigo === targetCodigo) {
          filho.marcado = !filho.marcado;
        }
      });
    }
  });
  
  // 更新状态触发重新渲染
  setArrayGrupoNiveis(updatedArray);
};

3. 修复JSX渲染语法问题

原JSX中条件渲染的写法会报错,需用括号包裹返回内容,同时给循环元素添加key属性避免React警告:

return (
  <FormProvider>
    {arrayGrupoNiveis.map((nivelItem: any) => (
      nivelItem.menu === 1 ? (
        nivelItem.filhos.map((filho: any) => (
          <Box key={filho.id} sx={{ marginLeft: 4 }}>
            <FormControlLabel
              control={
                <Checkbox
                  checked={filho.marcado}
                  size="small"
                  onClick={() => handleCheckBox(filho.codigo)}
                />
              }
              label={filho.nome}
            />
          </Box>
        ))
      ) : (
        <Box key={nivelItem.id}></Box>
      )
    ))}
  </FormProvider>
);

完整修正代码

import { useState } from 'react';
import { FormProvider, FormControlLabel, Checkbox, Box } from '@mui/material';

let arrayNiveis = [
  {
    id: 1,
    codigo: 16,
    filhos: [
      {
        id: 2,
        codigo: 17,
        filhos: null,
        marcado: false,
        menu: 1,
        nivel: 1,
        nome: "Listar",
        opcao: 2,
        pai: 1
      },
      {
        id: 3,
        codigo: 19,
        filhos: null,
        marcado: false,
        menu: 1,
        nivel: 2,
        nome: "Disponível",
        opcao: 2,
        pai: 1
      }
    ],
    marcado: false,
    menu: 1,
    nivel: 0,
    nome: "MANUTENÇÃO DE SERIAIS",
    opcao: 2,
    pai: null
  }
];

const CheckboxComponent = () => {
  const [arrayGrupoNiveis, setArrayGrupoNiveis] = useState(arrayNiveis);

  const handleCheckBox = (targetCodigo: number) => {
    const updatedArray = JSON.parse(JSON.stringify(arrayGrupoNiveis));
    
    updatedArray.forEach(nivelItem => {
      if (nivelItem.filhos) {
        nivelItem.filhos.forEach(filho => {
          if (filho.codigo === targetCodigo) {
            filho.marcado = !filho.marcado;
          }
        });
      }
    });
    
    setArrayGrupoNiveis(updatedArray);
  };

  return (
    <FormProvider>
      {arrayGrupoNiveis.map((nivelItem: any) => (
        nivelItem.menu === 1 ? (
          nivelItem.filhos.map((filho: any) => (
            <Box key={filho.id} sx={{ marginLeft: 4 }}>
              <FormControlLabel
                control={
                  <Checkbox
                    checked={filho.marcado}
                    size="small"
                    onClick={() => handleCheckBox(filho.codigo)}
                  />
                }
                label={filho.nome}
              />
            </Box>
          ))
        ) : (
          <Box key={nivelItem.id}></Box>
        )
      ))}
    </FormProvider>
  );
};

export default CheckboxComponent;

额外说明

  • 如果数组层级更深(比如包含孙元素),可以将查找逻辑改成递归函数,确保能定位任意层级的目标元素。
  • JSON.parse(JSON.stringify())是简易深拷贝方式,若数组包含函数或特殊对象,建议使用Lodash的cloneDeep等专业工具。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 23:01:36