ReactJS:如何通过Checkbox更新数组中指定元素的状态
解决嵌套数组中Checkbox点击仅更新对应元素状态的问题
问题分析
你的代码存在几个关键问题导致无法正确更新单个Checkbox状态:
- 未传递元素标识:点击Checkbox时没有传入当前元素的唯一标识(如
codigo或id),无法定位要修改的元素。 - 直接修改状态数组:直接修改
arrayGrupoNiveis中的元素属性,没有通过setArrayGrupoNiveis创建新数组触发React重新渲染。 - 逻辑判断错误:
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
相关产品推荐
相关产品推荐

