如何选择RTK Query中由Mutation添加到缓存的数据?
如何选择RTK Query中由Mutation添加到缓存的数据?
我来给你梳理下这个问题——RTK Query的mutation默认不会自动把结果存入缓存(毕竟mutation主要是用来触发服务端修改操作的),所以要获取mutation返回的用户数据,有两种常用的思路,我结合你的登录场景给你讲清楚:
方案一:把mutation结果存入独立的Redux Slice(最推荐,适配你的原有代码)
登录状态这种属于客户端全局UI状态,其实不太适合存在RTK Query的服务端数据缓存里,官方也推荐这类状态单独用Slice管理。刚好你原来的代码就是用selectUser从Slice里取数据,那直接沿用这个模式就行:
- 先创建一个专门的auth Slice来存登录用户信息:
import { createSlice, PayloadAction } from '@reduxjs/toolkit'; import type { UserServiceResult } from '你的类型文件路径'; interface AuthState { currentUser: UserServiceResult | null; } const initialState: AuthState = { currentUser: null, }; const authSlice = createSlice({ name: 'auth', initialState, reducers: { setCurrentUser: (state, action: PayloadAction<UserServiceResult | null>) => { state.currentUser = action.payload; }, clearCurrentUser: (state) => { state.currentUser = null; }, }, }); export const { setCurrentUser, clearCurrentUser } = authSlice.actions; export const selectUser = (state: RootState) => state.auth.currentUser; export default authSlice.reducer;
- 然后在登录组件里,mutation成功后dispatch这个存用户的action:
import { useDispatch } from 'react-redux'; import { setCurrentUser } from '../slices/authSlice'; // ...其他导入 const LoginForm = () => { const dispatch = useDispatch(); const [loginUser, { isLoading: isUpdating }] = useLoginUserMutation(); const handleLogin = (credentials: UserCredentials) => { loginUser(credentials).unwrap().then((userServiceResult) => { if (userServiceResult.isSuccessful) { console.log("Successfully logged in", userServiceResult); toast.success("User authenticated.", {position: "top-right"}); // 把返回的用户信息存入auth Slice dispatch(setCurrentUser(userServiceResult)); } else { toast.error("User authentication failed.", {position: "top-right"}); } }).catch((err) => { // 处理请求失败的情况 toast.error("登录请求失败,请稍后重试", {position: "top-right"}); }); }; // ...表单渲染逻辑 };
这样你原来的const user = useAppSelector(selectUser);完全不用改,直接就能拿到登录后的用户信息,完美兼容原有代码。
方案二:让mutation结果存入RTK Query缓存(适合需要和服务端数据联动的场景)
如果你确实想把用户信息存在RTK Query的缓存里,那需要手动配置mutation来更新缓存。比如,假设你有一个getCurrentUser的Query用来获取当前登录用户信息,那可以在登录mutation成功后,更新这个Query的缓存:
- 先定义一个
getCurrentUser的Query:
// 在你的api slice里 getCurrentUser: builder.query<UserServiceResult, void>({ query: () => '/current-user', // 假设这个接口返回当前登录用户信息 providesTags: ['CurrentUser'], // 给这个Query打标签,方便mutation触发更新 }),
- 然后修改login mutation,添加
onQueryStarted来更新缓存:
loginUser: builder.mutation<UserServiceResult, UserCredentials>({ query: ({ userName, password }) => ({ url: '/authenticate', method: 'POST', body: { UserName: userName, Password: password }, }), async onQueryStarted(args, { dispatch, queryFulfilled }) { try { const { data: userServiceResult } = await queryFulfilled; if (userServiceResult.isSuccessful) { // 更新getCurrentUser的缓存数据 dispatch( api.util.updateQueryData('getCurrentUser', undefined, () => { return userServiceResult; }) ); // 或者也可以用invalidatesTags让Query重新请求 // dispatch(api.util.invalidateTags(['CurrentUser'])); } } catch (err) { // 处理mutation失败的情况 } }, }),
- 之后在组件里,你就可以用
useGetCurrentUserQuery来获取用户信息了:
const { data: currentUser } = useGetCurrentUserQuery(); // 如果不想在未登录时自动发起请求,可以加skip选项 // const { data: currentUser } = useGetCurrentUserQuery(undefined, { skip: !isAuthenticated });
不推荐的方案:直接从mutation缓存里选数据
你也可以直接写Selector从RTK Query内部的mutation缓存里捞数据,但这种方法完全依赖RTK Query的内部实现结构,后续版本可能会变,维护成本高,不推荐。比如:
const selectLoginUserResult = (state: RootState) => { // 遍历mutation缓存,找到最新的loginUser结果 const allMutations = Object.values(state.api.mutations); const loginMutations = allMutations.filter(mut => mut.endpointName === 'loginUser'); // 取最后一次成功的mutation结果 return loginMutations.length > 0 ? loginMutations[loginMutations.length - 1].data : null; }; // 组件里使用 const loginResult = useAppSelector(selectLoginUserResult);
最后总结下,登录状态这种客户端UI状态,优先用方案一的独立Slice管理,逻辑清晰且兼容原有代码;如果是和服务端强绑定的数据,再考虑方案二的RTK Query缓存更新。
备注:内容来源于stack exchange,提问作者user101289
相关产品推荐
相关产品推荐

