
在 react 中调用异步登录函数时,若错误地对已 `await` 的结果再次传入 `toast.promise()`,会导致 toast 加载状态卡住——因为 `toast.promise` 必须接收一个 **promise 实例**,而非已解析的值。
toast.promise(promise, options) 是一个专为处理 Promise 状态(pending / fulfilled / rejected)而设计的工具方法。它内部会监听传入 Promise 的生命周期,并自动切换 loading、success 和 error 提示。但前提是:你必须传入一个未被 await 或 .then() 消费过的原始 Promise 对象。
来看你原始代码的问题所在:
onSubmit: async (values) => {
let loginPromise = await verifyPassword({ /* ... */ }); // ❌ 错误:这里已 await,loginPromise 是 resolved 值(如 { data: {...} }),不再是 Promise!
toast.promise(loginPromise, { /* ... */ }); // ⚠️ 传入的是普通对象 → toast 无法监听状态 → loading 一直显示
loginPromise.then((res) => { /* ... */ }); // ❌ loginPromise 已不是 Promise,.then 无效(静默失败)
},✅ 正确做法是:保留 verifyPassword(...) 返回的 Promise,直接传给 toast.promise,再 await 它的返回值(即最终响应)。toast.promise 本身会返回你传入的同一个 Promise(经包装增强),因此可链式 await 获取结果:
onSubmit: async (values) => {
// ✅ 正确:loginPromise 是 Promise 实例
const loginPromise = verifyPassword({
username,
password: values.password,
});
// ✅ toast.promise 接收 Promise,并返回它(支持 await)
const res = await toast.promise(loginPromise, {
loading: "Checking...",
success: Login successfully...,
error: Incorrect Password,
});
// ✅ 此时 res 即 verifyPassword resolve 的值(如 { data: { token } })
const { token } = res.data;
localStorage.setItem("token", token);
navigate("/profile");
},⚠️ 补充注意事项:
- 不要混用 await 和 .then() 处理同一 Promise(易引发竞态或重复执行);
- verifyPassword 内部已 await axios.post(...),外部无需再 await 两次;
- 若需全局错误兜底(如网络异常未被捕获),可在 toast.promise 外层加 try/catch,但通常 toast.error 已覆盖业务错误;
- verifyOTP 示例能正常工作,正是因为 await verifyOTP(...) 是直接等待结果并手动处理,未涉及 toast.promise —— 二者适用场景不同:toast.promise 用于「需要 UI 反馈 Promise 状态」,纯 await 适用于「仅需结果、自行控制提示」。
总结:await 用于获取 Promise 结果;toast.promise 用于将 Promise 的状态映射到 UI。二者目标不同,不可替代,更不可叠加滥用。 记住口诀:“传 Promise 给 toast,用 await 拿结果”。










