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

React中按钮点击触发状态变更导致表单无法提交的原因

问题

点击Save按钮时,希望在执行setUpdatingName(false)状态变更的同时触发所在<form>的提交,但添加状态变更后表单不再提交,移除该逻辑则表单能正常提交,这是为什么?

代码示例

function Item({name, _key})
{
   console.log('rendering Item')
   const [updatingName, setUpdatingName] = useState(false);
   const nameInputElement = useRef();

   useEffect(() => {
      if (updatingName) {
         nameInputElement.current.focus();
      }
   }, [updatingName]);

   function onUpdateClick() {
      setUpdatingName(true);
   }

   function onCancelClick() {
      setUpdatingName(false);
   }

   return (
      <div>
         <input ref={nameInputElement} type="text" defaultValue={name} name="name"
         disabled={!updatingName} />

         {!updatingName
         ? <>
            <button key={1} type="button" onClick={onUpdateClick}>Update</button>
            <button key={2} type="submit" name="delete" value={_key}>Remove</button>
         </>
         : <>
            <button key={3} type="submit" name="update" onClick={(e) => {setUpdatingName(false)}}>Save</button>
            <button key={4} type="button" onClick={onCancelClick}>Cancel</button>
         </>}
      </div>
   )
}

function ItemList({title})
{
   return <>
      <h1>{title}</h1>
      <form method="post" onSubmit={(e) => {console.log('submitting');e.preventDefault()}}>
         <Item name={'small'} _key={0} />
      </form>
   </>
}

export default ItemList;
原因解析

点击type="submit"按钮时,浏览器的事件执行顺序是:先触发按钮的onClick事件,再触发表单的onSubmit事件。

但在onClick中调用setUpdatingName(false)会立即触发React组件重渲染:Item组件的updatingName状态改变,原本显示的Save、Cancel按钮会被替换成Update、Remove按钮,这会导致当前的按钮和相关DOM节点被卸载。表单的onSubmit事件依赖原DOM节点存在才能完成触发流程,DOM被卸载后,后续的onSubmit事件就被中断了,所以控制台不会输出提交日志。

解决方案

方案1:将状态更新移到表单onSubmit回调中

把Save按钮的onClick逻辑移除,转而在表单的提交事件里处理状态变更(通过状态提升实现):

  1. 修改Item组件的Save按钮:
<button key={3} type="submit" name="update">Save</button>
  1. 状态提升,将updatingName和setUpdatingName移到ItemList组件,通过props传递给Item:
function ItemList({title}) {
  const [updatingName, setUpdatingName] = useState(false);
  return <>
    <h1>{title}</h1>
    <form method="post" onSubmit={(e) => {
      console.log('submitting');
      e.preventDefault();
      // 根据提交按钮的name判断是否是保存操作
      if (e.nativeEvent.submitter.name === 'update') {
        setUpdatingName(false);
      }
    }}>
      <Item name={'small'} _key={0} updatingName={updatingName} setUpdatingName={setUpdatingName} />
    </form>
  </>
}

这样表单提交流程不会被中断,提交完成后再更新状态,更符合React数据流规范。

方案2:延迟状态更新

利用setTimeout将状态更新放到宏任务队列,等表单提交事件处理完成后再执行重渲染:

<button key={3} type="submit" name="update" onClick={(e) => {
  setTimeout(() => setUpdatingName(false), 0);
}}>Save</button>

这种方式简单直接,适合快速修复场景。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.08 15:15:39