React-router 表单异步提交后调用history.push未实际重定向的问题
问题核心根因
你遇到的异常本质是表单原生提交的默认行为未被手动阻止,和异步回调内的路由跳转产生了执行时序冲突。
两种绑定场景的实际执行时序可以直接拆解开对比:
- 绑定同步执行的
test函数时:onSubmit事件触发后,同步逻辑会立刻执行history.push("/boards"),在事件处理的同步阶段就把地址栏、内存中的路由状态修改为/boards;等同步逻辑全部跑完,表单触发原生提交的整页刷新行为时,浏览器刚好会加载已经被修改后的/boards地址,属于歪打正着实现了跳转效果,因此你完全感知不到底层的隐患。 - 绑定异步的
submitHandler时:- onSubmit事件触发后,同步逻辑仅执行了发起
fetch请求的动作,函数立刻返回,全程没有修改任何路由状态 - 同步逻辑跑完后,浏览器立刻触发表单原生提交的默认行为——向当前路径/发起整页文档导航,准备重载整个页面
- 等网络请求返回后,异步回调里的
history.push("/boards")才会执行,刚把地址栏短暂修改为/boards,就被之前已经触发的整页导航重载动作打断,内存里的路由状态被重置回初始的/路径,这就是你观察到“地址栏闪一下又切回原地址”的根本原因。
- onSubmit事件触发后,同步逻辑仅执行了发起
具体解决方式
在onSubmit的事件处理函数最开头的同步执行段,调用事件对象的preventDefault()方法,彻底掐断表单原生的整页提交行为,就不会出现后续路由状态被重载冲掉的问题。
修正后的代码参考:
const submitHandler = (event) => { // 必须放在同步执行的最开头,绝对不能放到fetch的回调里 event.preventDefault(); fetch(...) .then((res) => res.json()) .then((result) => { history.push("/boards"); }); };
容易踩的误区
很多人会图省事把event.preventDefault()写到fetch的.then()回调里,这种写法完全没有效果——等回调执行的时候,表单的原生提交行为已经触发,根本来不及阻止。
额外提醒:哪怕是同步执行的
test函数,没有加preventDefault也是存在长期隐患的。一旦后续你把test里的逻辑改成异步实现,立刻就会复现现在的跳转失效问题。最好从项目一开始就对所有表单提交的onSubmit处理统一加上event.preventDefault(),从根源上避免原生浏览器行为干扰SPA的路由逻辑。
内容的提问来源于stack exchange,提问作者Phelizer
相关产品推荐
相关产品推荐

