如何为Redux-Toolkit自定义selectId?解决Valorant API数据加载异常
问题解决:Redux Entity Adapter警告与特工列表显示不全
核心问题分析
你遇到的两个问题直接关联:
- Redux警告
the entity passed from selectId returned undefined:createEntityAdapter默认用id作为实体唯一标识,但Valorant API返回的特工数据以uuid作为唯一ID,导致适配器无法识别有效标识。 - 仅显示1个特工:所有实体的标识被判定为
undefined,每次调用addOne都会覆盖同一个实体位置,最终只保留最后一条数据。
具体修复步骤
1. 自定义Entity Adapter的selectId函数
创建适配器时,明确指定使用uuid作为实体唯一标识:
const valorantAdapter = createEntityAdapter({ selectId: (agent) => agent.uuid // 替换默认id字段为uuid });
2. 优化数据批量添加逻辑
原代码中用forEach循环调用addOne可以替换为addMany,一次性添加所有特工数据,代码更简洁且性能更优:
.addCase(fetchValorants.fulfilled, (state, action) => { state.status = "succeeded"; // 替换forEach循环为addMany批量操作 valorantAdapter.addMany(state, action.payload); })
修改后的完整Slice代码
import { createAsyncThunk, createSlice } from "@reduxjs/toolkit"; import { createEntityAdapter } from "@reduxjs/toolkit"; import axios from "axios"; // 配置自定义selectId的Entity Adapter const valorantAdapter = createEntityAdapter({ selectId: (agent) => agent.uuid }); const initialState = valorantAdapter.getInitialState({ status: "idle", error: "" as any, }); export const fetchValorants = createAsyncThunk( "valorants/fetchValorants", async () => { const response = await axios .get("https://valorant-api.com/v1/agents") .then((response) => response.data.data) .then((agents) => { return Promise.all( agents.map((agent: any) => axios.get(`https://valorant-api.com/v1/agents/${agent.uuid}`) ) ); }) .then((agentDetails) => { return agentDetails.map((response) => response.data.data); }); return response; } ); const valorantsSlice = createSlice({ name: "valorants", initialState, reducers: {}, extraReducers(builder) { builder .addCase(fetchValorants.pending, (state, action) => { state.status = "loading"; }) .addCase(fetchValorants.fulfilled, (state, action) => { state.status = "succeeded"; // 使用addMany批量添加数据 valorantAdapter.addMany(state, action.payload); }) .addCase(fetchValorants.rejected, (state, action) => { state.status = "failed"; state.error = action.error.message; }); }, }); export default valorantsSlice.reducer; export const { selectAll: selectAllValorants, selectById: selectValorantByUuid, selectIds: selectValorantUuids, } = valorantAdapter.getSelectors((state: any) => state.valorants) as any;
额外优化建议
- 异步逻辑可简化:第一次调用
/v1/agents时已经返回了所有特工的完整数据,无需再逐个请求详情接口,直接返回response.data.data即可减少不必要的网络请求。 - 完善类型定义:建议给
agent编写TypeScript接口,避免使用any类型,提升代码健壮性。
内容的提问来源于stack exchange,提问作者Muhammad Yafi A
相关产品推荐
相关产品推荐

