React组件提交按钮点击后.then代码未执行的问题排查与修复
问题描述
点击「Save settings」按钮时,Settings组件的onsubmit函数中,除if语句及.then块内的代码外,其余代码均正常执行,但.then块代码未运行。相关代码如下:
Settings组件代码
import React, {useRef, useState } from "react" import { updateUser } from "../api callers/User" import Loader from "../components/Loader/Loader" import { useUser } from "./General" export default function Settings(){ let user=useUser() let reminderViaEmailShouldBeSendTo=useRef<HTMLInputElement|null>(null) let reminderViaPhoneShouldBeSendTo=useRef<HTMLInputElement|null>(null) let [isSavingSettings, setIsSavingSettings]=useState(false) function onsubmit(event:React.FormEvent<HTMLFormElement>){ event.preventDefault(); if (reminderViaPhoneShouldBeSendTo.current==null || reminderViaEmailShouldBeSendTo .current==null){ return; } setIsSavingSettings(true) updateUser(user.email, { reminderViaPhoneShouldBeSendTo:reminderViaPhoneShouldBeSendTo.current.value, reminderViaEmailShouldBeSendTo:reminderViaEmailShouldBeSendTo.current.value }, user.authToken).then( x=>{ setIsSavingSettings(false) } ) } if (user.authToken==""){ return <Loader></Loader> } if (isSavingSettings){ return <div className="center"> Saving settings ... </div> } return <form className="container" onSubmit={onsubmit}> <br></br> <label>Reminder via email should be send to</label> <br></br> <input type="email" ref={reminderViaEmailShouldBeSendTo} defaultValue={user.reminderViaEmailShouldBeSendTo}></input> <br></br> <br></br> <label>Reminder via phone should be send to</label> <br></br> <input type="text" ref={reminderViaPhoneShouldBeSendTo} defaultValue={ user.reminderViaPhoneShouldBeSendTo } ></input> <br></br> <br></br> <button className="blue-button" >Save settings</button> </form> }
updateUser函数代码
export function updateUser(email: string, object: { reminderViaEmailShouldBeSendTo?: string, reminderViaPhoneShouldBeSendTo?: string }, authorizationToken: string) { return callAnApiWithSomeJson(urlOfTheServer + "users/" + email, "PUT", authorizationToken, object) }
callAnApiWithSomeJson函数代码
export function callAnApiWithSomeJson( url: string, method: string, accessToken: string = "", json?:Object ) { return new Promise((resolve, reject) => { console.log(json); fetch(url, { headers: { Authorization: `Bearer ${accessToken}`, 'Content-Type':'application/json' }, method: method, body: JSON.stringify(json), keepalive:true, }) .then((result) => {result.json().then((result) => resolve(result))}) .catch((error) => reject(error)); }); }
原因分析
- fetch的HTTP错误未被捕获:fetch仅在网络故障时触发
catch,对于4xx/5xx这类HTTP错误状态码,仍会进入then分支。若此时响应无法解析为JSON,result.json()会抛出错误,但该错误未被捕获,导致外层Promise永远处于pending状态,updateUser的.then回调无法执行。 - 手动封装Promise的错误处理缺失:
callAnApiWithSomeJson手动创建Promise,但内部result.json()的错误未被处理,一旦解析失败,Promise既不会resolve也不会reject,后续逻辑彻底卡住。 - 未处理Promise的reject分支:
onsubmit仅监听了updateUser的成功回调,未处理错误分支,若请求出错,setIsSavingSettings(false)永远不会执行,同时错误无法被排查。
修复方案
1. 完善callAnApiWithSomeJson的错误处理
去掉冗余的手动Promise封装,直接使用fetch的Promise链,同时处理HTTP错误和JSON解析错误:
export function callAnApiWithSomeJson( url: string, method: string, accessToken: string = "", json?: Object ) { console.log(json); return fetch(url, { headers: { Authorization: `Bearer ${accessToken}`, 'Content-Type': 'application/json' }, method: method, body: JSON.stringify(json), keepalive: true, }) .then((result) => { // 捕获HTTP错误状态码 if (!result.ok) { throw new Error(`请求失败,状态码:${result.status}`); } return result.json(); }); }
2. 为onsubmit添加错误处理
确保请求无论成功或失败,都能重置isSavingSettings状态:
function onsubmit(event: React.FormEvent<HTMLFormElement>) { event.preventDefault(); if (reminderViaPhoneShouldBeSendTo.current == null || reminderViaEmailShouldBeSendTo.current == null) { return; } setIsSavingSettings(true); updateUser(user.email, { reminderViaPhoneShouldBeSendTo: reminderViaPhoneShouldBeSendTo.current.value, reminderViaEmailShouldBeSendTo: reminderViaEmailShouldBeSendTo.current.value }, user.authToken) .then(x => { setIsSavingSettings(false); }) .catch(error => { console.error("保存设置失败:", error); setIsSavingSettings(false); // 可选:添加用户可见的错误提示,比如弹窗或文字提示 }); }
3. 可选:用async/await简化代码
将onsubmit改为异步函数,代码逻辑更清晰:
async function onsubmit(event: React.FormEvent<HTMLFormElement>) { event.preventDefault(); if (reminderViaPhoneShouldBeSendTo.current == null || reminderViaEmailShouldBeSendTo.current == null) { return; } setIsSavingSettings(true); try { await updateUser(user.email, { reminderViaPhoneShouldBeSendTo: reminderViaPhoneShouldBeSendTo.current.value, reminderViaEmailShouldBeSendTo: reminderViaEmailShouldBeSendTo.current.value }, user.authToken); } catch (error) { console.error("保存设置失败:", error); // 可选:添加用户错误提示 } finally { // 无论成功失败都重置状态 setIsSavingSettings(false); } }
内容的提问来源于stack exchange,提问作者Justin Chan
相关产品推荐
相关产品推荐

