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

Firebase中updateDoc()失败时如何阻止Redux dispatch执行

实现方案

核心逻辑很简单:所有依赖Firebase更新成功的操作(包括Redux dispatch、成功提示等),必须放在await updateDoc()执行完成之后,绝对不能写到异步逻辑的外面。

之前代码的问题

  • 第一版把成功提示、dispatch写在异步函数调用的外层,JS的异步逻辑是非阻塞的,调用updateData()之后不会等它执行完,会立刻跑后面的同步代码,不管更新成没成都会触发本地状态修改,必然出现数据不一致。
  • 第二版虽然把dispatch挪到了await后面,但有几个明显bug:一是写了两个await重复调用updateDoc,会发两次重复的更新请求;二是靠window.navigator.onLine判断网络状态完全不可靠,这个API只能识别设备有没有连路由器/网卡,识别不了有没有实际公网连接,比如连了断网的wifi、请求中途断网的场景根本判断不出来;三是没有做重复点击防护,用户快速点多次会发多个并发请求,可能出现旧请求覆盖新状态的问题。

最终可靠实现

直接用try/catch包裹整个异步流程就行,不需要自己额外做网络前置判断——Firebase SDK本身会把所有失败场景(没网、权限不足、参数非法、服务端报错)都以抛出错误的形式返回,只要await updateDoc()没抛错,就代表文档已经在Firebase侧更新成功,这时候再触发dispatch就不会有问题。

首先在组件里加个ref做请求锁,防止重复触发:

const isUpdatingRef = useRef(false);

然后是事件处理逻辑:

const handleColor = async (e: React.FormEvent<HTMLInputElement>): Promise<void> => {
    // 重复点击直接拦截,避免并发请求
    if (isUpdatingRef.current) return;
    isUpdatingRef.current = true;

    const targetColorValue = colors[e.currentTarget.value];
    const docRef = doc(db, 'collection', currentUser.uid);

    try {
        // 等待Firebase确认更新成功,这一步抛错会直接跳去catch块,不会执行后面的dispatch
        await updateDoc(docRef, { customColor: targetColorValue });
        // 到这一步100%更新成功,再更新本地Redux状态
        dispatch(addColor({ select: 'customColor', value: targetColorValue }));
    } catch (err: any) {
        let tip = '更新失败,请稍后重试';
        // 按错误码映射用户提示
        switch (err?.code) {
            case 'network-request-failed':
            case 'unavailable':
                tip = '网络连接异常,请检查网络后重试';
                break;
            case 'permission-denied':
                tip = '无权限修改该配置';
                break;
            // 其他错误码按需加映射即可
        }
        alert(tip);
    } finally {
        // 不管成功失败都释放锁
        isUpdatingRef.current = false;
    }
};

几个关键说明

  • 不需要自己提前判断网络状态:Firebase SDK抛出的network-request-failed、unavailable错误已经覆盖了所有网络异常场景,包括连不上网、请求超时、服务端不可用,比自己写navigator.onLine判断靠谱得多。
  • updateDoc本身返回Promise<void>,只要这个Promise正常resolve(不抛错),就代表服务端已经持久化写入成功,不需要额外判断返回值,逻辑和调用MongoDB接口判断响应成功是一样的。
  • 不要在try块外面、异步函数外面写任何依赖更新成功的逻辑,否则一定会出现更新失败但本地状态先改了的不一致问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.28 11:27:22