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

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();
}, []);

感谢您的帮助。


问题解决

核心问题分析

  1. API数据结构访问错误:API返回的response.data.data.organizations是数组,而非对象,直接访问.name会得到undefined,导致表单值变为undefined,触发受控组件转非受控的警告。
  2. 字段名不匹配:API返回字段为comment,但代码中使用comments;parent_org_id对应代码中的parentOrg,字段名不一致导致赋值失败。
  3. 重复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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.22 18:36:40