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

React表单提交时dispatch异步Redux Action导致应用重置问题排查

问题描述

我需要dispatch一个携带表单内容的Action,这个Action包含由自定义中间件处理的异步逻辑。该Action在React外部初始化数据时运行正常,在组件加载时通过无依赖项的useEffect调用也能正常工作——Redux Store会更新,API调用也可成功执行(正常代码示例如下):

import { React, useState, useEffect } from "react"
import { useSelector, useDispatch } from "react-redux"
import { apiCallBegan } from "../store/api"
const NewQuestionForm = () => {
  // const [optionOneText, setOptionOneText] = useState("")
  // const [optionTwoText, setOptionTwoText] = useState("")
  const [submitted, setSubmitted] = useState(false);
  // const author = useSelector(state => state.auth)
  const dispatch = useDispatch()
  useEffect(()=>{
    dispatch(apiCallBegan({
      callMethodName: '_saveQuestion',
      data: { optionOneText: "I believe I can fly", optionTwoText: "I donte believe I can Fly", author:'helenfoneing' },
      onSuccess: ['questions/questionAdded','users/questionAdded'],
      onError: 'apiRequestfailed'
    } ))
  },[])
  return (
    <form className="new-question-form"
      // ... rest of component
    </form>)
}

但是当尝试在表单提交时触发该Action时,整个应用会发生重置,效果如同按下浏览器F5刷新键。我已将Action数据硬编码以隔离问题,但仍未找到原因(有问题的代码示例如下):

/* eslint-disable no-unused-vars */
/* eslint-disable react/prop-types */
// TODO: upgrade to latest eslint tooling
import { React, useState, useEffect } from "react"
import { useSelector, useDispatch } from "react-redux"
import { apiCallBegan } from "../store/api"
const NewQuestionForm = () => {
  const [optionOneText, setOptionOneText] = useState("")
  const [optionTwoText, setOptionTwoText] = useState("")
  const [submitted, setSubmitted] = useState(false);
  const author = useSelector(state => state.auth)
  const dispatch = useDispatch()
  useEffect(()=>{
    submitted && dispatch(apiCallBegan({
      callMethodName: '_saveQuestion',
      data: { optionOneText: "I believe I can fly", optionTwoText: "I donte believe I can Fly", author:'helenfoneing' },
      onSuccess: ['questions/questionAdded','users/questionAdded'],
      onError: 'apiRequestfailed'
    } ))
  },[submitted])
  return (
    <form className="new-question-form"
      onSubmit={(e)=>{
        setSubmitted(true)
        e.preventDefault
      } }
    >
      NEW QUESTION FORM HERE
      <label>1. <input type="text" value={optionOneText} onChange={(e) => setOptionOneText(e.target.value)} /></label>
      <label>2. <input type="text" value={optionTwoText} onChange={(e) => setOptionTwoText(e.target.value)} /></label>
      <input type="submit" />
    </form>)
}
export default NewQuestionForm

请问该问题的原因是什么?


问题原因与解决方案

嘿,这个问题我一眼就看出来啦——你在表单提交的回调里犯了一个很容易忽略的小错误!

浏览器里表单的默认行为就是提交后刷新页面,你本来想通过e.preventDefault阻止这个行为,但你只是引用了这个方法,没有真正调用它!少了一对括号,就导致preventDefault根本没执行,浏览器还是会触发默认的页面刷新,所以整个应用才会像按了F5一样重置。

快速修复

把onSubmit的回调改成这样,给preventDefault加上括号调用:

onSubmit={(e)=>{
  e.preventDefault(); // 这里一定要加括号执行方法
  setSubmitted(true);
} }

更简洁的写法

其实你完全不用通过submitted状态配合useEffect来触发dispatch,直接在onSubmit回调里调用dispatch会更直观,还能少写一些状态相关的代码:

onSubmit={(e)=>{
  e.preventDefault();
  // 直接在这里dispatch你的Action
  dispatch(apiCallBegan({
    callMethodName: '_saveQuestion',
    data: { optionOneText: "I believe I can fly", optionTwoText: "I donte believe I can Fly", author:'helenfoneing' },
    onSuccess: ['questions/questionAdded','users/questionAdded'],
    onError: 'apiRequestfailed'
  }));
} }

这样修改后,表单提交时就会正常触发你的异步Action,同时不会触发页面刷新,应用也就不会重置啦。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.30 17:17:48