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

React使用现有对象初始化useState失败问题求助

问题:React模态框表单初始化值异常

我是React新手,想在模态框中收集表单数据并发送请求,同时让输入框从传入的props.itemInfo获取默认值。尝试用props.itemInfo的属性初始化formData状态,但控制台显示itemInfo.itemID为3,formData.itemID却为undefined,传入的对象数据正常,求问题原因及可行实现方案。

相关代码

function Parent() {
  const [state, setState] = useState(false);
  const [itemInfo, setItemInfo] = useState({})

  // itemInfo get from somewhere in the middle

  return (
    <div>
      <button onClick={() => setState(true)}> Render modal </button>
      <Modal itemInfo={itemInfo} state={state} setState={setState} />
    </div>
  )
};


function Modal(props) {
  let itemInfo = props.itemInfo;
  console.log(typeof itemInfo); // 1
  console.log(itemInfo);        // 2

  /* I also tried 
    const [formData, setFormData] = useState({itemInfo});
    but not working
  */

  const [formData, setFormData] = useState({
    itemID: itemInfo.itemID,
    userID: itemInfo.userID,
    isActive: itemInfo.isActive,
    purchaseCost: itemInfo.purchaseCost,
    dateModified: itemInfo.dateModified,
    dateCreated: itemInfo.dateCreated,
    description: itemInfo.description,
    itemGrouping: itemInfo.itemGrouping,
  });
  console.log(itemInfo.itemID); // 3
  console.log(formData.itemID); // 4

  const handleCloseModal = () => {
    props.setState(false);
  };

  const handleFormChange = (e) => {
    const { id, value } = e.target;
    setFormData((prevState) => ({
      ...prevState,
      [id]: value,
    }));
  };
  const handleSubmit = (e) => {
    e.preventDefault();
    // send request with formData
  };
  return (
    <ReactModal isOpen={props.state} ariaHideApp={false}>
      <form id="login">
        <div>
          <label>Grouping: </label>
          <input
            id="grouping"
            type="text"
            defaultValue={formData.itemGrouping}
            onChange={handleFormChange}
            required
          />
        </div>
        <div>
          <label>Cost: </label>
          <input
            id="cost"
            type="text"
            defaultValue={formData.purchaseCost}
            onChange={handleFormChange}
            required
          />
        </div>
        <div>
          <label>Description: </label>
          <input
            id="description"
            type="text"
            defaultValue={formData.description}
            onChange={handleFormChange}
            required
          />
        </div>
        <button type="submit" onClick={handleSubmit}>
          Submit
        </button>
      </form>
      <button onClick={handleCloseModal}>Close Modal</button>
    </ReactModal>
  );
}

传入的对象数据

{
    "itemID": 3,
    "userID": 2,
    "isActive": 1,
    "purchaseCost": 0,
    "dateModified": "2022-10-05 03:44:07",
    "dateCreated": "2022-10-05",
    "description": "Gift from my sister for my 29th birthday!",
    "itemGrouping": null
}

控制台输出

object        // 1

{
    "itemID": 3,
    "userID": 2,
    "isActive": 1,
    "purchaseCost": 0,
    "dateModified": "2022-10-05 03:44:07",
    "dateCreated": "2022-10-05",
    "description": "Gift from my sister for my 29th birthday!",
    "itemGrouping": null
}              // 2

3              // 3

undefined      // 4

问题原因

  1. useState初始化特性:React的useState初始化值仅在组件首次渲染时执行一次。你的Parent组件中itemInfo初始值是空对象{},此时Modal首次渲染,formData会用空对象的属性初始化(所有值都是undefined)。后续itemInfo更新为完整数据时,useState的初始化逻辑不会再次触发,所以formData仍保持首次渲染的undefined值。
  2. 控制台日志时序:你看到的itemInfo.itemID为3是组件更新后的日志,但formData的初始化已经在首次渲染完成,不会随itemInfo的更新自动同步。

可行实现方案

方案1:用useEffect监听props变化同步formData

通过useEffect监听props.itemInfo的更新,手动同步formData状态,确保每次模态框拿到新数据时,表单默认值能同步更新。

修改后的Modal组件代码:

function Modal(props) {
  // 先初始化空状态
  const [formData, setFormData] = useState({
    itemID: '',
    userID: '',
    isActive: '',
    purchaseCost: '',
    dateModified: '',
    dateCreated: '',
    description: '',
    itemGrouping: '',
  });

  // 监听itemInfo变化,同步更新formData
  useEffect(() => {
    // 确保有有效数据时再更新
    if (props.itemInfo?.itemID) {
      setFormData({
        itemID: props.itemInfo.itemID,
        userID: props.itemInfo.userID,
        isActive: props.itemInfo.isActive,
        purchaseCost: props.itemInfo.purchaseCost,
        dateModified: props.itemInfo.dateModified,
        dateCreated: props.itemInfo.dateCreated,
        description: props.itemInfo.description,
        itemGrouping: props.itemInfo.itemGrouping,
      });
    }
  }, [props.itemInfo]); // 依赖项设为itemInfo,变化时触发

  const handleCloseModal = () => {
    props.setState(false);
  };

  const handleFormChange = (e) => {
    const { id, value } = e.target;
    // 修正输入框id与formData的key一致,确保更新正确字段
    setFormData((prevState) => ({
      ...prevState,
      [id]: value,
    }));
  };

  const handleSubmit = (e) => {
    e.preventDefault();
    console.log('提交数据:', formData);
    // 此处发送请求
  };

  return (
    <ReactModal isOpen={props.state} ariaHideApp={false}>
      <form id="itemForm" onSubmit={handleSubmit}>
        <div>
          <label>Grouping: </label>
          <input
            id="itemGrouping" // 修正id与formData的key匹配
            type="text"
            value={formData.itemGrouping ?? ''} // 用value实现受控组件,处理null值
            onChange={handleFormChange}
            required
          />
        </div>
        <div>
          <label>Cost: </label>
          <input
            id="purchaseCost" // 修正id
            type="number" // 成本用number类型更合理
            value={formData.purchaseCost}
            onChange={handleFormChange}
            required
          />
        </div>
        <div>
          <label>Description: </label>
          <input
            id="description"
            type="text"
            value={formData.description}
            onChange={handleFormChange}
            required
          />
        </div>
        <button type="submit">Submit</button>
      </form>
      <button onClick={handleCloseModal}>Close Modal</button>
    </ReactModal>
  );
}

额外优化点

  • 将表单改为受控组件(用value替代defaultValue),确保表单数据与formData状态完全同步。
  • 修正输入框id与formData的key一致,避免handleFormChange无法正确更新字段。
  • 处理itemGrouping为null的情况,用?? ''转为空字符串避免输入框报错。

方案2:控制Modal渲染时机

在Parent组件中,只有当itemInfo有完整数据时才渲染Modal,避免首次渲染用空对象初始化:

function Parent() {
  const [state, setState] = useState(false);
  const [itemInfo, setItemInfo] = useState({})

  return (
    <div>
      <button onClick={() => setState(true)}> Render modal </button>
      {/* 只有itemInfo有itemID时才渲染Modal */}
      {itemInfo.itemID && <Modal itemInfo={itemInfo} state={state} setState={setState} />}
    </div>
  )
};

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.17 13:35:34