React组件外获取RTK Query数据?TypeScript类型问题求助
我正在开发基于 React TypeScript 的应用,使用 RTK Query,想要实现自定义选择器,但需要从另一个端点获取数据:
store.dispatch(userApiSlice.endpoints.check.initiate(undefined)) const data = userApiSlice.endpoints.check.getSomeData export const selectCartItemsResult = cartApiSlice.endpoints.getCartItems .select(data?.user?.id ?? skipToken)
我找到一个解决方案示例:
class TodoService { getSelectorForTodo(todoId: string) { if (this._lastId !== todoId) this._lastSelector = api.endpoints.getTodo.select( {id: todoId } ) return this._lastSelector } getTodoTitle( todoId: string ) { const todo = this.getSelectorForTodo(todoId)(state) return todo.data.title } }
但我不知道 state 变量从何处获取,尝试用 store.getState() 却出现类型错误:
const data = userApiSlice.endpoints.check .select(undefined)(store.getState())
报错信息:
The types of 'api.queries' are incompatible between these types.
Type 'QueryState<{ getCartItems: QueryDefinition<number, BaseQueryFn<string | FetchArgs, unknown, FetchBaseQueryError, {}, FetchBaseQueryMeta>, "cart", EntityState<...>, "api">; clearCart: MutationDefinition<...>; addItem: MutationDefinition<...>; changeItemQuantity: MutationDefinition<...>; changeItemSize: MutationDefini...' is not assignable to type 'QueryState<{ registration: MutationDefinition<IRegisterBody, BaseQueryFn<string | FetchArgs, unknown, FetchBaseQueryError, {}, FetchBaseQueryMeta>, "cart", IUserApiState, "api">; login: MutationDefinition<...>; check: QueryDefinition<...>; }>'.
补充说明:cartApiSlice 和 userApiSlice 是通过 injectEndpoints 创建的。
需要一个能通过 TypeScript 编译、正确声明 state 变量的示例。
1. 导出统一的 RootState 类型
首先从 store 文件导出正确的全局状态类型,这是解决类型不兼容的核心:
// store.ts import { configureStore } from '@reduxjs/toolkit' import { baseApi } from './services/baseApi' // 你的基础 API 切片(所有 injectEndpoints 基于此扩展) export const store = configureStore({ reducer: { [baseApi.reducerPath]: baseApi.reducer, }, middleware: (getDefaultMiddleware) => getDefaultMiddleware().concat(baseApi.middleware), }) // 导出全局状态类型 export type RootState = ReturnType<typeof store.getState>
2. 创建跨端点的组合选择器
用 createSelector 组合两个端点的选择器,避免直接硬编码调用 store.getState():
import { createSelector } from '@reduxjs/toolkit' import { skipToken } from '@reduxjs/toolkit/query/react' import { userApiSlice } from './userApi' import { cartApiSlice } from './cartApi' import type { RootState } from '../store' // 第一步:获取用户校验接口的缓存数据 const selectUserCheckData = userApiSlice.endpoints.check.select(undefined) // 第二步:组合选择器,根据用户ID获取对应购物车数据 export const selectCartItemsByUser = createSelector( (state: RootState) => selectUserCheckData(state), (userResult) => { const userId = userResult.data?.user?.id // 无用户ID时返回 skipToken,让RTK Query跳过请求 return cartApiSlice.endpoints.getCartItems.select(userId ?? skipToken) }, // 第三步:最终获取购物车数据 (_, cartSelector) => cartSelector(store.getState()) )
3. 组件中使用选择器
在 React 组件中结合 useSelector 和 RTK Query 的 hooks 使用:
import { useSelector, useEffect } from 'react-redux' import { useLazyQuery } from '@reduxjs/toolkit/query/react' import { userApiSlice } from './userApi' import { selectCartItemsByUser } from './selectors' import type { RootState } from '../store' function CartComponent() { const [triggerUserCheck] = useLazyQuery(userApiSlice.endpoints.check) const cartResult = useSelector((state: RootState) => selectCartItemsByUser(state)) // 组件挂载时触发用户校验 useEffect(() => { triggerUserCheck() }, [triggerUserCheck]) if (cartResult.isLoading) return <div>加载中...</div> if (cartResult.error) return <div>加载失败</div> return ( <div className="cart-items"> {cartResult.data?.map(item => ( <div key={item.id}>{item.name} × {item.quantity}</div> ))} </div> ) }
4. 类型错误原因说明
你之前遇到的类型不匹配,是因为单个 API 切片的选择器默认只识别自身切片的状态结构,而全局 RootState 包含所有扩展后的 API 状态。通过统一导出 RootState 并在选择器中明确指定,就能让 TypeScript 正确推断跨切片的状态类型。
内容的提问来源于stack exchange,提问作者Demian

