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

React中无法更新嵌套数组元素state的解决方法

问题根因

你的代码存在5个核心错误,直接导致状态更新失效、数据结构错乱:

  • 接口请求直接写在组件函数体内,组件每次重渲染都会重复触发请求,造成无限重渲染循环
  • changeValue 里的状态更新逻辑完全错误:map 遍历时不匹配的项没有返回原内容,匹配项的更新逻辑错误拼接了整个旧列表,还额外给结果多套了一层数组,直接把原本的二维数组结构改坏
  • 单选框触发change事件时调用了event.preventDefault(),会阻止单选框本身的默认选中行为
  • 提交按钮是submit类型,点击时没有阻止表单默认提交行为,会触发页面刷新,所有内存中的状态直接清空
  • JSX中label的for属性不符合React语法要求,需要写成htmlFor,否则会抛出控制台警告
修正步骤
  1. 把GET接口请求放到useEffect钩子中,配置空依赖数组,保证只在组件首次挂载时执行一次,避免重复请求
  2. 重写changeValue的状态更新逻辑:遍历列表时,非匹配项直接原样返回,匹配到对应name的项时,保留前两个字段,把第三个binary字段替换为当前选中的value,使用函数式更新避免闭包拿到旧状态值导致更新异常
  3. 移除change事件里的event.preventDefault(),不要干预单选框的原生交互逻辑
  4. 给表单提交事件加默认行为阻止,避免页面刷新
  5. 把label的for属性替换为htmlFor,符合React的JSX语法规范
修正后的完整代码
import React, { useState, useEffect } from "react";
import Axios from "axios";

function Attendance() {
  const [attedanceList, setAttedanceList] = useState([]);

  // 接口请求移到useEffect,仅组件首次挂载时执行
  useEffect(() => {
    Axios.get("http://localhost:9000/attendance").then((response) => {
      setAttedanceList(response.data.data.values);
    });
  }, []);

  function changeValue(event) {
    const { name, value } = event.target;
    // 函数式更新,规避闭包旧值问题
    setAttedanceList(prevList => 
      prevList.map(items => {
        // 匹配到当前修改的用户行,替换第三个binary值,其余字段保持不变
        if (items[0] === name) {
          return [items[0], items[1], value];
        }
        // 非匹配行直接原样返回
        return items;
      })
    );
  }

  function sendAllValues(event) {
    // 阻止表单默认提交导致的页面刷新
    event.preventDefault();
    Axios.post("http://localhost:9000/attendance", { attedanceList });
  }

  return (
    <form onSubmit={sendAllValues}>
      {attedanceList.map((val, index) => {
        // 跳过第一行表头数据
        if (index !== 0) {
          const presentId = `present${index}`;
          const absentId = `absent${index}`;
          return (
            <div key={index}>
              <div>
                {val[0]} {val[1]}
                <input
                  type="radio"
                  id={presentId}
                  name={val[0]}
                  value="1"
                  checked={val[2] === "1"}
                  onChange={changeValue}
                />
                <label htmlFor={presentId}>Present</label>
                <input
                  type="radio"
                  id={absentId}
                  name={val[0]}
                  value="0"
                  checked={val[2] === "0"}
                  onChange={changeValue}
                />
                <label htmlFor={absentId}>Absent</label>
              </div>
            </div>
          );
        }
        return null;
      })}
      <button type="submit">
        Submit
      </button>
    </form>
  );
}

export default Attendance;
效果说明
  • 修正后每次点击单选框,只会更新对应用户行的binary值,其余行数据完全不受影响
  • 状态更新后单选框的checked属性会自动和最新状态同步,选中状态不会错乱
  • 提交时直接取最新的attedanceList传给后端即可,数据结构和接口初始返回的格式完全一致,不需要额外转换

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.26 19:24:22