如何将createApi获取的用户数据存储到Redux Store中?
如何将RTK Query获取的用户数据存入Redux Store?
我想把通过createApi获取的用户数据(姓名、邮箱等)存储到Redux Store的authSlice中,但不清楚具体实现方法和最佳实践。以下是我的代码示例:
userApi.js
export const userApi = createApi({ reducerPath: "userApi", baseQuery: fetchBaseQuery({ baseUrl: "http://localhost:5000" , credentials: "include", tagTypes: ['Users'], prepareHeaders: (headers, { getState }) => { const { accessToken } = getState().auth; if (accessToken) { headers.set('Authorization', `Bearer ${accessToken}`); } return headers; } }), endpoints: (builder) => ({ getUsers: builder.query({ query: () => "/users", providesTags: ["Users"], transformResponse: (response) => response.data, }), loginUser: builder.mutation({ query: (value) => ({ url: "/login", method: "POST", body: value, }) }), // 其他端点... }) }); export const { useGetUsersQuery, useLoginUserMutation } = userApi;
authSlice.js
const initialState = { user: null, accessToken : null, } const authSlice = createSlice({ name: "auth", initialState, reducers: { setUser: (state, action) => { state.user = action.payload; }, setAccessToken: (state, action) => { state.accessToken = action.payload; }, logOut: () => initialState }, }) export const { setUser, setAccessToken, logOut } = authSlice.actions; export default authSlice.reducer export const selectUser = (state) => state.auth.user; export const selectAccessToken = (state) => state.auth.accessToken;
我之前了解过可以使用extraReducer和addCase,但不确定这是否是最佳实践。
实现方案与最佳实践
方法一:用extraReducers监听RTK Query异步动作
RTK Query会自动生成对应端点的异步动作类型,你可以在authSlice中通过extraReducers监听这些动作,实现数据自动存入state。
修改后的authSlice代码
import { createSlice } from '@reduxjs/toolkit'; import { userApi } from './userApi'; // 导入userApi const initialState = { user: null, accessToken: null, }; const authSlice = createSlice({ name: 'auth', initialState, reducers: { setUser: (state, action) => { state.user = action.payload; }, setAccessToken: (state, action) => { state.accessToken = action.payload; }, logOut: () => initialState, }, extraReducers: (builder) => { // 监听getUsers查询成功的动作 builder.addCase(userApi.endpoints.getUsers.matchFulfilled, (state, action) => { // 根据你的接口返回结构调整,这里假设返回的是用户数组,取第一个 state.user = action.payload[0]; }); // 监听loginUser mutation成功的动作 builder.addCase(userApi.endpoints.loginUser.matchFulfilled, (state, action) => { // 假设登录接口返回包含accessToken和user的对象 state.accessToken = action.payload.accessToken; state.user = action.payload.user; }); // 可选:监听请求失败的动作,处理错误场景 builder.addCase(userApi.endpoints.getUsers.matchRejected, (state) => { state.user = null; }); }, }); export const { setUser, setAccessToken, logOut } = authSlice.actions; export default authSlice.reducer; export const selectUser = (state) => state.auth.user; export const selectAccessToken = (state) => state.auth.accessToken;
这种方式的优势是自动化同步,不需要在组件中手动处理,只要请求成功就自动更新全局state,适合认证信息这类需要全局共享的数据。
方法二:组件内手动dispatch动作
如果需要在存储数据前做额外处理(比如数据校验、格式转换),可以在组件中调用RTK Query的hook,拿到数据后手动触发setUser或setAccessToken动作。
组件示例代码
import { useEffect } from 'react'; import { useDispatch } from 'react-redux'; import { useGetUsersQuery, useLoginUserMutation } from './userApi'; import { setUser, setAccessToken } from './authSlice'; function UserPage() { const dispatch = useDispatch(); // 调用getUsers查询hook const { data: users, isSuccess } = useGetUsersQuery(); // 查询成功后手动存储用户数据 useEffect(() => { if (isSuccess && users?.length > 0) { // 这里可以添加数据处理逻辑 const processedUser = { ...users[0], fullName: `${users[0].firstName} ${users[0].lastName}` }; dispatch(setUser(processedUser)); } }, [isSuccess, users, dispatch]); // 登录逻辑示例 const [login] = useLoginUserMutation(); const handleLogin = async (formData) => { const result = await login(formData); if (result.data) { dispatch(setAccessToken(result.data.accessToken)); dispatch(setUser(result.data.user)); } }; return ( <div> {/* UI内容 */} </div> ); }
最佳实践总结
- 优先选择
extraReducers:对于认证信息这类全局共享的数据,extraReducers能实现自动化同步,减少组件内的重复逻辑,代码更简洁。 - 避免冗余存储:如果RTK Query的缓存数据已经能满足UI渲染需求,无需额外存入authSlice——RTK Query本身提供了缓存、自动重取等机制。只有当需要在非组件逻辑(比如中间件、其他slice)中访问这些数据时,才需要存入独立slice。
- 匹配接口返回结构:无论哪种方式,都要根据实际接口的返回格式调整
action.payload的处理逻辑,确保数据正确存入state。 - 处理错误场景:记得监听
matchRejected动作,在请求失败时清空或重置相关state,避免脏数据残留。
内容的提问来源于stack exchange,提问作者Josh Lee
相关产品推荐
相关产品推荐

