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

如何使用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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 15:45:53