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

如何选择RTK Query中由Mutation添加到缓存的数据?

如何选择RTK Query中由Mutation添加到缓存的数据?

我来给你梳理下这个问题——RTK Query的mutation默认不会自动把结果存入缓存(毕竟mutation主要是用来触发服务端修改操作的),所以要获取mutation返回的用户数据,有两种常用的思路,我结合你的登录场景给你讲清楚:

方案一:把mutation结果存入独立的Redux Slice(最推荐,适配你的原有代码)

登录状态这种属于客户端全局UI状态,其实不太适合存在RTK Query的服务端数据缓存里,官方也推荐这类状态单独用Slice管理。刚好你原来的代码就是用selectUser从Slice里取数据,那直接沿用这个模式就行:

  1. 先创建一个专门的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;
  1. 然后在登录组件里,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的缓存:

  1. 先定义一个getCurrentUser的Query:
// 在你的api slice里
getCurrentUser: builder.query<UserServiceResult, void>({
  query: () => '/current-user', // 假设这个接口返回当前登录用户信息
  providesTags: ['CurrentUser'], // 给这个Query打标签,方便mutation触发更新
}),
  1. 然后修改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失败的情况
    }
  },
}),
  1. 之后在组件里,你就可以用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.13 20:09:37