RTK Query发送POST请求后列表未新增数据,求排查解决
问题原因分析
你遇到的核心问题是my-json-server是模拟API服务:它的POST请求只会返回模拟的成功响应,但不会实际修改后端仓库中的数据。所以当你通过invalidatesTags: ['Users']触发重新拉取列表时,拿到的还是原始的旧数据,自然看不到新增的项。
解决方案
方案一:乐观更新(推荐)
直接在本地更新RTK Query的缓存,不用依赖后端的真实写入,同时保留请求失败时的回滚逻辑,提升用户体验。
修改你的addUser mutation:
addUser: builder.mutation({ query: (body) => ({ url: '/karolkproexe/jsonplaceholderdb/data', method: 'POST', body, }), transformResponse: (response) => response, async onQueryStarted(newUser, { dispatch, queryFulfilled }) { // 第一步:乐观更新本地缓存 const patchResult = dispatch( apiUsersSlice.util.updateQueryData('getUsers', undefined, (draft) => { // 构造符合transformResponse格式的用户数据 const formattedUser = { id: newUser.id || Date.now(), // 用临时ID,后续用服务器返回的ID替换 name: newUser.name, username: newUser.username, city: newUser.address?.city, email: newUser.email, }; draft.push(formattedUser); }) ); try { // 等待请求完成,拿到服务器返回的真实ID const { data } = await queryFulfilled; dispatch( apiUsersSlice.util.updateQueryData('getUsers', undefined, (draft) => { const targetIndex = draft.findIndex(user => user.id === (newUser.id || Date.now())); if (targetIndex !== -1) { draft[targetIndex].id = data.id; } }) ); } catch (err) { // 请求失败时回滚乐观更新 patchResult.undo(); } }, }),
- 移除
invalidatesTags,因为我们手动更新了缓存,无需重新拉取无效的后端数据
方案二:结合LocalStorage持久化数据
把用户列表缓存到LocalStorage,新增数据时同步更新本地缓存,刷新页面后仍能看到新增项。
修改你的slice代码:
import { createApi, fetchBaseQuery } from "@reduxjs/toolkit/query/react"; const STORAGE_KEY = 'users_cache'; // 读取本地缓存 const getCachedUsers = () => { const cached = localStorage.getItem(STORAGE_KEY); return cached ? JSON.parse(cached) : null; }; // 写入本地缓存 const setCachedUsers = (users) => { localStorage.setItem(STORAGE_KEY, JSON.stringify(users)); }; export const apiUsersSlice = createApi({ reducerPath: "apiUsersSlice", baseQuery: fetchBaseQuery({ baseUrl: "https://my-json-server.typicode.com", }), tagTypes: ['Users'], endpoints: (builder) => ({ getUsers: builder.query({ query: () => "/karolkproexe/jsonplaceholderdb/data", providesTags: ['Users'], transformResponse: (response) => { const formattedData = response.map((obj) => ({ id: obj.id, name: obj.name, username: obj.username, city: obj.address.city, email: obj.email, })); // 首次加载时写入缓存 if (!getCachedUsers()) { setCachedUsers(formattedData); } // 优先返回本地缓存数据 return getCachedUsers() || formattedData; }, }), addUser: builder.mutation({ query: (body) => ({ url: '/karolkproexe/jsonplaceholderdb/data', method: 'POST', body, }), transformResponse: (response) => response, async onQueryStarted(newUser, { dispatch, queryFulfilled }) { const { data } = await queryFulfilled; // 构造格式化后的用户数据 const formattedUser = { id: data.id, name: newUser.name, username: newUser.username, city: newUser.address?.city, email: newUser.email, }; // 更新LocalStorage缓存 const currentUsers = getCachedUsers() || []; currentUsers.push(formattedUser); setCachedUsers(currentUsers); // 更新RTK Query缓存 dispatch( apiUsersSlice.util.updateQueryData('getUsers', undefined, (draft) => { draft.push(formattedUser); }) ); }, }), }), }); export const { useGetUsersQuery, useAddUserMutation } = apiUsersSlice;
额外注意
你的index.js中导入了ApiProvider但未使用,当前写法无需添加ApiProvider,因为configureStore已经集成了RTK Query的reducer和middleware,保持现有代码即可。
内容的提问来源于stack exchange,提问作者Bartosz Rowiński
相关产品推荐
相关产品推荐

