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
相关产品推荐
相关产品推荐

