如何使用RTK Query处理Lookup数据并完整存储至Redux
问题描述
我需要在应用加载时把数据库里的查询表(Lookup Tables)一次性加载到Redux的单个Slice中。后端返回的JSON包含custTypes和nationalities两个数组,但用RTK Query的createEntityAdapter处理后,Redux里只存了custTypes的数据,怎么修改才能存储完整的返回对象?
后端返回的JSON数据:
{ "custTypes": [ { "code": 1, "name": "افراد" }, { "code": 2, "name": "شركات" }, { "code": 3, "name": "ccc" } ], "nationalities": [ { "code": 3, "name": "السعوديه" }, { "code": 4, "name": "تركيا" }, { "code": 5, "name": "الاردن" }, { "code": 6, "name": "ليتوانيا" }, { "code": 7, "name": "الصين" } ] }
现有API Slice代码:
import { createEntityAdapter, createSelector } from "@reduxjs/toolkit"; import { apiSlice } from "../../App/api/apiSlice"; const custLookupsAdapter = createEntityAdapter(); const initialState = custLookupsAdapter.getInitialState(); export const customerLookupsApiSlice = apiSlice.injectEndpoints({ endpoints: (builder) => ({ getCustomerLookups: builder.query({ query: () => "/sales/customerlookups", transformResponse: (res) => { return custLookupsAdapter.setAll(initialState, res); }, }), }), }); export const { useGetCustomerLookupsQuery } = customerLookupsApiSlice; export const selectCustomerLookupResult = customerLookupsApiSlice.endpoints.getCustomerLookups.select(); export const selectCustomerLookupData = createSelector( selectCustomerLookupResult, (customerLookup) => customerLookup.data ); export const { selectAll: selectAllCustomerLookups } = custLookupsAdapter.getSelectors( (state) => selectCustomerLookupData(state) ?? initialState );
解决方案
问题根源
createEntityAdapter是用来管理单一类型的实体集合(比如一个用户数组)的工具,你现在用它的setAll方法去处理整个返回对象(包含两个不同数组),但setAll要求第二个参数是实体数组,传入对象后会被错误解析,导致只存储了部分数据。
根据你的需求,有两种可行的修改方式:
方式一:直接存储完整返回对象(无需EntityAdapter)
如果你不需要EntityAdapter提供的CRUD操作、标准化实体结构等功能,直接存储原始返回对象是最简单的方案:
修改后的代码:
import { createSelector } from "@reduxjs/toolkit"; import { apiSlice } from "../../App/api/apiSlice"; export const customerLookupsApiSlice = apiSlice.injectEndpoints({ endpoints: (builder) => ({ getCustomerLookups: builder.query({ query: () => "/sales/customerlookups", // 移除transformResponse,直接返回原始数据 }), }), }); export const { useGetCustomerLookupsQuery } = customerLookupsApiSlice; export const selectCustomerLookupResult = customerLookupsApiSlice.endpoints.getCustomerLookups.select(); export const selectCustomerLookupData = createSelector( selectCustomerLookupResult, (customerLookup) => customerLookup.data ?? { custTypes: [], nationalities: [] } ); // 分别创建获取两个集合的选择器 export const selectAllCustTypes = createSelector( selectCustomerLookupData, (data) => data.custTypes ); export const selectAllNationalities = createSelector( selectCustomerLookupData, (data) => data.nationalities );
方式二:为每个集合创建独立的EntityAdapter
如果你需要利用EntityAdapter的标准化状态、CRUD方法等功能,可以为custTypes和nationalities分别创建Adapter,然后合并它们的状态:
修改后的代码:
import { createEntityAdapter, createSelector } from "@reduxjs/toolkit"; import { apiSlice } from "../../App/api/apiSlice"; // 为两个集合分别创建EntityAdapter const custTypesAdapter = createEntityAdapter({ selectId: (entity) => entity.code // 指定唯一标识字段为code }); const nationalitiesAdapter = createEntityAdapter({ selectId: (entity) => entity.code }); // 初始化合并后的状态 const initialState = { custTypes: custTypesAdapter.getInitialState(), nationalities: nationalitiesAdapter.getInitialState() }; export const customerLookupsApiSlice = apiSlice.injectEndpoints({ endpoints: (builder) => ({ getCustomerLookups: builder.query({ query: () => "/sales/customerlookups", transformResponse: (res) => { return { // 分别用各自的Adapter处理对应数组 custTypes: custTypesAdapter.setAll(initialState.custTypes, res.custTypes), nationalities: nationalitiesAdapter.setAll(initialState.nationalities, res.nationalities) }; }, }), }), }); export const { useGetCustomerLookupsQuery } = customerLookupsApiSlice; export const selectCustomerLookupResult = customerLookupsApiSlice.endpoints.getCustomerLookups.select(); export const selectCustomerLookupData = createSelector( selectCustomerLookupResult, (customerLookup) => customerLookup.data ?? initialState ); // 为每个集合生成选择器 export const { selectAll: selectAllCustTypes, selectById: selectCustTypeById } = custTypesAdapter.getSelectors( (state) => selectCustomerLookupData(state).custTypes ); export const { selectAll: selectAllNationalities, selectById: selectNationalityById } = nationalitiesAdapter.getSelectors( (state) => selectCustomerLookupData(state).nationalities );
内容的提问来源于stack exchange,提问作者Gado
相关产品推荐
相关产品推荐

