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

React useState更新对象state时出现渲染报错如何解决

问题描述

编译运行Attendance组件时抛出如下运行时错误:

Uncaught Error: Objects are not valid as a React child (found: object with keys {present1}). If you meant to render a collection of children, use an array instead.
(中文释义:React不允许直接将对象作为子元素渲染,检测到包含键{present1}的对象。如果需要渲染子元素集合,请改用数组格式。)

错误根因

这个报错本质是JSX渲染阶段尝试直接渲染JavaScript对象触发的,结合业务代码,一共有4个问题共同导致异常:

  • 接口请求直接写在组件函数顶层,没有做调用时机控制,每次组件重渲染都会触发请求,请求返回更新状态又触发重渲染,形成无限循环。
  • 单选框的checked判断逻辑错误:attendanceMarking是存储所有行考勤结果的对象,直接将整个对象和字符串"1"/"0"做相等判断,既无法正确匹配选中状态,也会在状态更新时触发渲染类型异常。
  • map遍历考勤列表时,第一行(index=0)的分支没有显式返回值,默认返回undefined,叠加状态更新的异常容易触发渲染校验失败。
  • JSX语法使用不规范:label标签的for属性和JavaScript保留关键字冲突,需要使用JSX规定的htmlFor属性;提交按钮没有阻止表单默认提交行为,点击后会刷新页面。
修复方案

替换为如下修复后的代码即可解决问题:

import React, { useState, useEffect } from "react";
import Axios from "axios";

function Attendance() {
  const [attendanceList, setAttendanceList] = useState([]);
  const [attendanceMarking, setAttendanceMarking] = useState({});

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

  function changeValue(event) {
    const { name, value } = event.target;
    setAttendanceMarking(prev => ({...prev, [name]: value }));
  }

  function sendAllValues(event) {
    // 阻止表单默认提交刷新行为
    event.preventDefault();
    Axios.post("http://localhost:9000/attendance", { attendanceMarking });
  }

  return (
    <form onSubmit={sendAllValues}>
      {attendanceList.map((val, index) => {
        // 表头行直接返回null,不渲染内容
        if (index === 0) return null;
        
        const attendanceKey = `attendance${index}`;
        const presentId = `present${index}`;
        const absentId = `absent${index}`;

        return (
          <div key={index}>
            <div>
              {val[0]} {val[1]}
              <input
                type="radio"
                id={presentId}
                name={attendanceKey}
                value="1"
                // 取对象中对应key的值判断选中状态
                checked={attendanceMarking[attendanceKey] === "1"}
                onChange={changeValue}
              />
              {/* JSX中用htmlFor替代for属性 */}
              <label htmlFor={presentId}>Present</label>
              <input
                type="radio"
                id={absentId}
                name={attendanceKey}
                value="0"
                checked={attendanceMarking[attendanceKey] === "0"}
                onChange={changeValue}
              />
              <label htmlFor={absentId}>Absent</label>
            </div>
          </div>
        );
      })}
      <button type="submit">
        Submit
      </button>
    </form>
  );
}

export default Attendance;
避坑说明

后续写React代码时注意以下规则,可以规避同类报错:

  • 所有带副作用的逻辑(接口请求、订阅、定时器)必须放在useEffect中控制执行时机,不要直接写在组件函数顶层。
  • JSX中渲染的变量必须是合法的渲染类型:字符串、数字、合法的React组件/元素可正常渲染,布尔值/undefined/null会被直接忽略,永远不要直接把普通对象等非合法类型直接放在JSX渲染位置。
  • 表单受控组件的状态判断要精准取到对应字段的值,不要直接拿整个状态对象做判断。
  • 遍历生成元素时所有分支都要有明确的返回值,不渲染的分支显式返回null。
  • 注意JSX和原生HTML的属性差异:for写成htmlFor、class写成className,避免语法冲突。

内容的提问来源于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 18:18:52