React+Redux Toolkit Query操作Firestore创建文档触发无效Hook调用错误
Redux Toolkit Query + Firestore:Invalid Hook Call错误修复与最佳实践
错误原因
- 违反Hooks规则:你在
onSubmit事件回调里直接调用useQuery,React Hooks只能在函数组件顶层或自定义Hooks中调用,不能嵌套在事件处理、循环、条件判断里,这是触发Invalid Hook Call的直接原因。 - API设计不符合RTK Query规范:用
builder.query处理Firestore文档创建是错误的——RTK Query中,query专门用于只读数据请求(比如获取文档列表),**写操作(新增/修改/删除)**必须用builder.mutation。
修复方案
第一步:将createDoc改为Mutation
修改RTK Query API定义,把createDoc从builder.query替换为builder.mutation,并导出对应的Hook:
import { createApi, fakeBaseQuery } from '@reduxjs/toolkit/query/react'; import { addDoc, collection, getDoc } from 'firebase/firestore'; import { db } from './your-firebase-config'; // 替换为你的Firestore配置路径 export const itemsApi = createApi({ reducerPath: "itemsApi", baseQuery: fakeBaseQuery(), endpoints: (builder) => ({ createDoc: builder.mutation<{ title: string }, string>({ async queryFn(title) { try { const ref = await addDoc(collection(db, "items"), { title }); const snap = await getDoc(ref); return { data: snap.data()! as { title: string } }; } catch (error) { return { error }; } }, }), // 保留你已有的查询端点(比如getItems) }), }); // 导出mutation Hook供组件使用 export const { useCreateDocMutation } = itemsApi;
第二步:调整表单组件逻辑
在组件顶层获取mutation触发函数,在onSubmit中调用该函数而非直接调用Hook:
import { useState } from 'react'; import { useCreateDocMutation } from './your-api-path'; // 替换为你的API路径 export const NewItemForm = () => { const [title, setTitle] = useState(""); // 在组件顶层获取mutation触发函数和状态(加载/错误) const [createDoc, { isLoading, error }] = useCreateDocMutation(); const changeTitle = (e: React.ChangeEvent<HTMLInputElement>) => { setTitle(e.target.value); }; const onSubmit = async (e: React.ChangeEvent<HTMLFormElement>) => { e.preventDefault(); if (!title.trim()) return; try { await createDoc(title); // 成功后重置表单 setTitle(""); } catch (err) { console.error("创建文档失败:", err); } }; return ( <form onSubmit={onSubmit}> <input type="text" value={title} onChange={changeTitle} disabled={isLoading} placeholder="输入标题" /> <button type="submit" disabled={isLoading}> {isLoading ? "创建中..." : "Create Item"} </button> {error && <p style={{ color: 'red', marginTop: '8px' }}>创建失败,请重试</p>} </form> ); };
关于适配Firestore的疑问
- 是否应该用builder.mutation?:完全应该。RTK Query的
mutation就是为写操作设计的,它自动管理加载状态、错误状态,还支持缓存更新(比如创建文档后自动刷新列表缓存),比手动写Redux slice更高效。 - 是否属于强行适配?:不算。RTK Query官方支持用
fakeBaseQuery配合自定义queryFn适配非REST/GraphQL数据源(比如Firestore),这是官方推荐的方案。如果RTK Query的缓存、状态管理特性对你有用,用它对接Firestore是合理选择;若需求简单,也可以直接用Firebase SDK配合React状态,或普通Redux slice处理。
内容的提问来源于stack exchange,提问作者psygo
相关产品推荐
相关产品推荐

