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

React/Redux项目中无法删除Firestore文档的报错问题求助

Redux Toolkit 结合 Firestore 实现CRUD时文档删除功能报错

问题现象

  • 基于Redux Toolkit与Firestore搭建CRUD应用过程中,Firestore文档删除功能始终无法正常运行,多次调整实现方式后仍未定位失效原因
  • 运行时抛出固定错误信息:

Cannot use 'in' operator to search for '_delegate' in undefined

  • 已尝试的排查操作:
    • 传入硬编码测试数据触发删除函数,问题未解决
    • 移除DELETE_RECIPE reducer后运行代码,故障依然存在
    • 最初判断QuerySnapshot自带的forEach方法支持async/await写法,因此未使用createAsyncThunk,不确定该判断是否存在错误

问题关联代码

Slice 层实现

export const recipeSlice = createSlice({
    name: 'recipesSlice',
    initialState: {
        recipes: []
        
    },
    reducers: {
        ADD_RECIPE: (state, action) => {
            state.recipes.push(action.payload)
        },
        DELETE_RECIPE: (state, action) => {
            state.recipes = state.recipes.filter((recipe) => recipe.recipeId !== action.payload.recipeId)
        }
    }
})

自定义删除Thunk实现

export const deleteRecipe = ({recipeId}) => {
        return async (dispatch) => {
            const q = query(collection(db, "recipes"), where("recipeId", "==", `${recipeId}`));
            const querySnapshot = await getDocs(q);
            querySnapshot.forEach(async(doc) => {
                console.log(doc.id, " => ", doc.data())
                await deleteDoc(doc)
            });
            dispatch(DELETE_RECIPE({recipeId}))
        }
}

故障根因

  • 核心报错诱因:deleteDoc() 方法要求入参必须是DocumentReference类型的文档引用对象,当前代码直接传入遍历得到的doc(QueryDocumentSnapshot快照实例),Firestore SDK内部尝试读取引用对象内置的_delegate属性时拿到undefined,直接抛出类型错误。
  • 隐藏逻辑缺陷:querySnapshot.forEach() 本质是同步遍历方法,即使是Firestore官方提供的遍历API,也不会等待内部异步回调的Promise执行,会直接执行后续dispatch逻辑,导致远端删除操作和本地Redux状态更新时序错乱。
  • 潜在代码风险:若未手动将slice对应reducer的action creator解构赋值为DELETE_RECIPE变量,直接调用DELETE_RECIPE()会触发未定义错误,标准调用方式为recipeSlice.actions.DELETE_RECIPE。

修复方案

替换原有删除thunk逻辑为以下实现即可:

export const deleteRecipe = ({recipeId}) => {
        return async (dispatch) => {
            // 移除不必要的模板字符串转义
            const q = query(collection(db, "recipes"), where("recipeId", "==", recipeId));
            const querySnapshot = await getDocs(q);
            const deleteTasks = []
            querySnapshot.forEach((doc) => {
                console.log(doc.id, " => ", doc.data())
                // 传入快照挂载的ref属性(即对应文档的引用对象)作为deleteDoc入参
                deleteTasks.push(deleteDoc(doc.ref))
            });
            // 等待所有远端删除操作完成
            await Promise.all(deleteTasks)
            // 再更新本地Redux状态,保证数据一致性
            dispatch(recipeSlice.actions.DELETE_RECIPE({recipeId}))
        }
}

补充说明

  • 该业务场景不需要强制使用createAsyncThunk,自定义thunk的写法完全适用,之前的判断没有错误。
  • 硬编码ID测试仍报错、移除本地reducer仍报错的核心原因是错误发生在Firestore SDK调用阶段,代码还未执行到dispatch逻辑,和入参值、本地reducer逻辑无关。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 03:09:19