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

React表单对象类型State更新时未修改属性被清空如何解决

问题根因

React 中useState的更新逻辑是全量替换状态值,不会自动合并对象属性。你代码里写的setFacility({ Name: e.target.value }),本质是把整个Facility状态替换成了只有Name属性的新对象,之前存在对象里的其他字段自然就被覆盖清空了。
另外你同时定义了9个零散的单字段state和1个统一的Facility对象state,两套状态完全独立不同步,就算解决了对象覆盖问题,最后提交时拿Facility序列化也会丢那些存在零散state里的字段值。

修复步骤
  • 删掉所有零散的单字段useState,所有表单字段统一收敛到Facility对象里管理,完全匹配你要直接JSON.stringify提交、后续抽HOC的需求。
  • 更新对象状态时,先通过展开运算符复制原有对象的所有属性,再覆盖当前要修改的字段,保证未修改的属性不丢失。推荐用函数式更新写法拿最新的前序状态,避免闭包导致拿到旧状态的问题:
    // 错误写法:直接替换整个对象,其他属性丢失
    onChange={(e) => setFacility({ Name: e.target.value })}
    
    // 正确写法:保留旧属性,仅覆盖当前修改字段
    onChange={(e) => setFacility(prev => ({ ...prev, Name: e.target.value }))}
    
  • 抽离通用的输入变更回调,给每个表单控件加name属性对应Facility里的字段名,不用每个输入框都写重复的onChange逻辑,后续重构可复用HOC时直接把这个回调当通用逻辑就行。
  • 给所有表单控件加上value属性绑定对应状态字段,做成标准受控组件,避免输入值和状态不一致的问题。
修复后完整代码
import React, { useState } from "react";
import { Form, Row, Col, Button, Container } from "react-bootstrap";

function FacilitiesCreate() {
  // 移除所有零散单字段state,统一管理表单状态
  const [Facility, setFacility] = useState({
    Name: "",
    Latitude: 0,
    Longitude: 0,
    Description: "",
    AddressLineOne: "",
    AddressLineTwo: "",
    City: "",
    State: "",
    ZipCode: "",
  }); 

  const createFacilityEndpoint = "https://localhost:7113/api/facilities";
  
  // 通用表单更新逻辑,后续抽HOC可以直接复用
  const handleInputChange = (e) => {
    const { name, value } = e.target;
    setFacility(prev => ({
      ...prev,
      // 经纬度字段转数字类型,其他字段保持字符串
      [name]: name === 'Latitude' || name === 'Longitude' ? Number(value) : value
    }))
  }

  const handleSubmit = async (event) => {
      event.preventDefault();
      // 现在可以直接序列化整个Facility对象,所有字段都不会丢失
      let response = await fetch(createFacilityEndpoint, {
        method: "POST",
        headers: {
          "Content-Type": "application/json;charset=utf-8",
        },
        body: JSON.stringify(Facility),
      });
      if (response.ok) {
        alert("提交成功");
      }
  };

  return (
    <Container>
      <h2>Create New Facility</h2>
      <p>facility name: {Facility.Name}</p>
      <br/>
      <p>address: {Facility.AddressLineOne}</p>
      <Form onSubmit={handleSubmit}>
        <Row className="mb-3">
          <Col>
            <Form.Label>Location Name</Form.Label>
            <Form.Control
              type="text"
              name="Name"
              placeholder="Location's Name"
              value={Facility.Name}
              onChange={handleInputChange}
            />
          </Col>

          <Col>
            <Form.Label>Latitude</Form.Label>
            <Form.Control
              type="number"
              step="any"
              name="Latitude"
              placeholder="Enter Latitude"
              value={Facility.Latitude}
              onChange={handleInputChange}
            />
          </Col>

          <Col>
            <Form.Label>Longitude</Form.Label>
            <Form.Control
              type="number"
              step="any"
              name="Longitude"
              placeholder="Enter Longitude"
              value={Facility.Longitude}
              onChange={handleInputChange}
            />
          </Col>
        </Row>
        <Row className="mb-3">
          <Col>
            <Form.Label>Description</Form.Label>
            <Form.Control
              as="textarea"
              rows={3}
              name="Description"
              placeholder="Enter Description"
              value={Facility.Description}
              onChange={handleInputChange}
            />
          </Col>
        </Row>

        <Form.Group className="mb-3" controlId="formGridAddress1">
          <Form.Label>Address</Form.Label>
          <Form.Control
            placeholder="1234 Main St"
            name="AddressLineOne"
            value={Facility.AddressLineOne}
            onChange={handleInputChange}
          />
        </Form.Group>

        <Form.Group className="mb-3" controlId="formGridAddress2">
          <Form.Label>Address 2</Form.Label>
          <Form.Control
            placeholder="Apartment, studio, or floor"
            name="AddressLineTwo"
            value={Facility.AddressLineTwo}
            onChange={handleInputChange}
          />
        </Form.Group>

        <Row className="mb-3">
          <Form.Group as={Col} controlId="formGridCity">
            <Form.Label>City</Form.Label>
            <Form.Control
              placeholder="Miami Beach"
              name="City"
              value={Facility.City}
              onChange={handleInputChange}
            />
          </Form.Group>

          <Form.Group as={Col} controlId="formGridState">
            <Form.Label>State</Form.Label>
            <Form.Control
              placeholder="FL"
              name="State"
              value={Facility.State}
              onChange={handleInputChange}
            />
          </Form.Group>

          <Form.Group as={Col} controlId="formGridZip">
            <Form.Label>Zip</Form.Label>
            <Form.Control
              placeholder="33141"
              name="ZipCode"
              value={Facility.ZipCode}
              onChange={handleInputChange}
            />
          </Form.Group>
        </Row>

        <Button variant="primary" type="submit">
          Submit
        </Button>
      </Form>
    </Container>
  );
}

export default FacilitiesCreate;

注:原代码中input的type="float"是非标准写法,修复后改为标准的type="number"搭配step="any",支持小数形式的经纬度输入。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 22:39:19