React表单无法渲染选中行数据,控制台出现受控组件警告
React表单无法填充数据及受控组件警告问题
我是React.js新手,若问题较为浅显还请见谅。我有一个数据列表,每行带有更新按钮,点击后应打开一个已填充selectedRow.data对应字段的表单,但表单控件为空。在Postman中请求对应URL可得到正确响应,因此排除API问题。
控制台出现如下警告:
Warning: A component is changing a controlled input to be uncontrolled. This is likely caused by the value changing from a defined to undefined, which should not happen. Decide between using a controlled or uncontrolled input element for the lifetime of the component
组织更新表单代码
import React, { useState, useContext, useEffect } from "react"; import { useParams, useNavigate } from "react-router-dom"; import { AppContext } from '../context/AppContext'; import AdminPortal from '../apis/AdminPortal' const OrganizationUpdateForm = (props) => { const {id} = useParams() const { organizations } = useContext(AppContext); const [name, setName] = useState(""); const [shortName, setShortName] = useState(""); const [parentOrg, setParentOrg] = useState(""); const [website, setWebsite] = useState(""); const [comments, setComments] = useState(""); useEffect(() => { async function fetchData () { const response = await AdminPortal.get(`organizations/${id}`); console.log(response.data.data); setName(response.data.data.organizations.name); setShortName(response.data.data.organizations.short_name); setParentOrg(response.data.data.organizations.parent_org); setWebsite(response.data.data.organizations.website); setComments(response.data.data.organizations.comments); }; fetchData(); }, []); let Navigate = useNavigate(); const handleSubmit = async (e) => { e.preventDefault(); const updateOrganization = await AdminPortal.put(`organizations/${id}`, { name, short_name: shortName, parent_org: parentOrg, website, comments }); Navigate("/"); }; return ( <div> <form action=''> <div className="form-group"> <label htmlFor='name'>Name</label> <input value={name} onChange={(e) => setName(e.target.value)} id="name" className="form-control" type="text" /> </div> <div className="form-group"> <label htmlFor='short_name'>Short Name</label> <input value={shortName} onChange={(e) => setShortName(e.target.value)} id="name" className="form-control" type="text" /> </div> <div className="form-group"> <label htmlFor='parent_org'>Parent Organization</label> <input value={parentOrg} onChange={(e) => setParentOrg(e.target.value)} id="name" className="form-control" type="text" /> </div> <div className="form-group"> <label htmlFor='website'>Website</label> <input value={website} onChange={(e) => setWebsite(e.target.value)} id="name" className="form-control" type="text" /> </div> <div className="form-group"> <label htmlFor='comments'>Comments</label> <input value={comments} onChange={(e) => setComments(e.target.value)} id="name" className="form-control" type="text" /> </div> {/* <button type="submit" onClick={handleSubmit} className="btn btn-primary" > Submit </button> */} </form> </div> ) } export default OrganizationUpdateForm
API响应示例(请求http://localhost:3000/api/v1/organizations/20)
{ "status": "success", "results": 1, "data": { "organizations": [ { "id": 20, "name": "International Aids Vaccine Initiative", "name_localized": "IAVI", "parent_org_id": null, "website": "", "comment": "", "create_date": "2019-08-26T12:42:49.457Z", "logo": null, "short_name": "IAVI" } ] } }
AdminPortal配置代码
import axios from "axios"; export default axios.create({ baseURL: "http://localhost:3000/api/v1/" })
网络响应说明
网络响应显示请求状态为200,返回数据结构与上述JSON示例一致。请求{id}的最后一行无响应,同时端口从3001变为3000,这点让我感到疑惑。
我尝试将数据获取路径修改为response.data.organizations,但并未解决问题,修改后的代码如下:
useEffect(() => { async function fetchData () { // const response = await AdminPortal.get(`organizations/${id}`); const response = await AdminPortal.get(`organizations/${id}`); console.log(response.dataorganizations); setName(response.data.organizations.name); setShortName(response.data.organizations.short_name); setParentOrg(response.data.organizations.parent_org); setWebsite(response.data.organizations.website); setComments(response.data.organizations.comments); }; fetchData(); }, []);
感谢您的帮助。
问题解决
核心问题分析
- API数据结构访问错误:API返回的
response.data.data.organizations是数组,而非对象,直接访问.name会得到undefined,导致表单值变为undefined,触发受控组件转非受控的警告。 - 字段名不匹配:API返回字段为
comment,但代码中使用comments;parent_org_id对应代码中的parentOrg,字段名不一致导致赋值失败。 - 重复input id:所有input的id均为
name,不符合HTML规范,可能导致标签关联失效。
修正后的代码
import React, { useState, useContext, useEffect } from "react"; import { useParams, useNavigate } from "react-router-dom"; import { AppContext } from '../context/AppContext'; import AdminPortal from '../apis/AdminPortal' const OrganizationUpdateForm = (props) => { const {id} = useParams() const { organizations } = useContext(AppContext); const [name, setName] = useState(""); const [shortName, setShortName] = useState(""); const [parentOrg, setParentOrg] = useState(""); const [website, setWebsite] = useState(""); const [comments, setComments] = useState(""); useEffect(() => { async function fetchData () { try { const response = await AdminPortal.get(`organizations/${id}`); // 取数组第一个元素 const org = response.data.data.organizations[0]; console.log(org); setName(org.name || ""); setShortName(org.short_name || ""); // 匹配API返回字段名 setParentOrg(org.parent_org_id || ""); setWebsite(org.website || ""); // 匹配API返回的comment字段 setComments(org.comment || ""); } catch (err) { console.error("获取数据失败:", err); } }; fetchData(); }, [id]); // 添加id依赖,参数变化时重新获取数据 let Navigate = useNavigate(); const handleSubmit = async (e) => { e.preventDefault(); try { const updateOrganization = await AdminPortal.put(`organizations/${id}`, { name, short_name: shortName, parent_org: parentOrg, website, // 提交时注意匹配后端字段要求 comments: comments }); Navigate("/"); } catch (err) { console.error("更新失败:", err); } }; return ( <div> <form onSubmit={handleSubmit}> {/* 用onSubmit绑定提交逻辑 */} <div className="form-group"> <label htmlFor='name'>Name</label> <input value={name} onChange={(e) => setName(e.target.value)} id="name" className="form-control" type="text" /> </div> <div className="form-group"> <label htmlFor='short_name'>Short Name</label> <input value={shortName} onChange={(e) => setShortName(e.target.value)} id="short_name" {/* 修正id与label对应 */} className="form-control" type="text" /> </div> <div className="form-group"> <label htmlFor='parent_org'>Parent Organization</label> <input value={parentOrg} onChange={(e) => setParentOrg(e.target.value)} id="parent_org" {/* 修正id与label对应 */} className="form-control" type="text" /> </div> <div className="form-group"> <label htmlFor='website'>Website</label> <input value={website} onChange={(e) => setWebsite(e.target.value)} id="website" {/* 修正id与label对应 */} className="form-control" type="text" /> </div> <div className="form-group"> <label htmlFor='comments'>Comments</label> <input value={comments} onChange={(e) => setComments(e.target.value)} id="comments" {/* 修正id与label对应 */} className="form-control" type="text" /> </div> <button type="submit" className="btn btn-primary" > Submit </button> </form> </div> ) } export default OrganizationUpdateForm
额外说明
- 端口变化是React开发服务器的正常行为:默认优先使用3000端口,若3000被占用则自动切换到其他可用端口。
- 添加
try/catch捕获请求错误,便于调试排查问题。 - useEffect依赖项添加
id,确保路由参数变化时重新加载对应数据。
内容的提问来源于stack exchange,提问作者A Cameron
相关产品推荐
相关产品推荐

