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
相关产品推荐
相关产品推荐

