RTK Query结合Selector使用:添加查询参数后Selector失效问题
问题原因与解决方案
核心问题是你当前的selectEntry selector没有接收filters参数,RTK Query会根据不同的filters缓存不同的查询结果,不带参数的selector无法匹配到对应缓存,所以加了filters后失效。
具体修改步骤
1. 重构Selector逻辑
你需要把selector改成带参数的工厂函数,让它能接收filters并定位到对应的缓存数据:
import { createSelector, createEntityAdapter } from '@reduxjs/toolkit' import { apiSlice } from './apiSlice' const entryAdapter = createEntityAdapter() const initialState = entryAdapter.getInitialState() export const entryApiSlice = apiSlice.injectEndpoints({ endpoints: (builder) => ({ getEntry: builder.query({ query: (filters) => ({ url: '/history', params: filters, }), transformResponse: (responseData) => { // 每次创建新的归一化状态,避免全局状态污染 return entryAdapter.setAll(entryAdapter.getInitialState(), responseData) }, providesTags: (result, error, arg) => [ { type: 'Entry', id: 'LIST' }, ...result.ids.map((id) => ({ type: 'Entry', id })), ], }), // 以下mutation逻辑保持不变 addEntry: builder.mutation({ query: (data) => ({ url: '/history/new', method: 'POST', body: data, }), invalidatesTags: [{ type: 'Entry', id: 'LIST' }], }), updateEntry: builder.mutation({ query: (initialEntry) => ({ url: `/history/${initialEntry.Id}`, method: 'PUT', body: { ...initialEntry, date: new Date().toISOString(), }, }), invalidatesTags: (result, error, arg) => [{ type: 'Entry', id: arg.id }], }), deleteEntry: builder.mutation({ query: ({ id }) => ({ url: `/history/${id}`, method: 'DELETE', body: { id }, }), invalidatesTags: (result, error, arg) => [{ type: 'Entry', id: arg.id }], }), }), }) export const { useGetEntryQuery, useAddEntryMutation, useUpdateEntryMutation, useDeleteEntryMutation, } = entryApiSlice // 1. 定义带参数的查询结果选择器 const selectEntryResult = (state, filters) => entryApiSlice.endpoints.getEntry.select(filters)(state)?.data ?? initialState // 2. 创建带参数的selectAll选择器 export const selectAllEntries = createSelector( [ (state) => state, (_, filters) => filters ], (state, filters) => { const normalizedData = selectEntryResult(state, filters) return entryAdapter.selectAll(normalizedData) } )
2. 组件中使用带参数的Selector
修改组件里的useSelector调用,传入当前的filters参数:
const { data: entriesData = [], refetch, isLoading, isSuccess, isError, error, } = useGetEntryQuery(filters) // 传入filters参数获取对应缓存的数组数据 const entries = useSelector(state => selectAllEntries(state, filters))
关键说明
- RTK Query的
select方法必须传入对应的查询参数(这里是filters),才能获取到该参数对应的缓存数据。 - 用
createSelector包裹带参数的逻辑,能让Redux缓存计算结果,避免不必要的组件重渲染。 transformResponse里不要复用全局的initialState,每次创建新的初始状态,防止状态污染。
内容的提问来源于stack exchange,提问作者Sotiris Gian
相关产品推荐
相关产品推荐

