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

能否通过传入ID数组使用useSelector从Redux Store中选择多个实体?

Solution for Selecting Multiple Redux Entities by ID Array

Great question! The issue you're hitting is a classic React Hook rules violation—you can't call hooks like useSelector inside loops, conditions, or nested functions. Let's fix this by fetching all the entities you need in a single useSelector call instead.

Here are a couple of robust approaches tailored to your Redux Toolkit setup:

1. Basic Custom Selector (Simple Implementation)

You can create a straightforward selector that takes the Redux state and your array of company IDs, then maps over the IDs to pull the corresponding entities from the companies slice.

First, define the selector function:

import { RootState } from '../path/to/your/store'; // Import your root state type

const selectCompaniesByIds = (state: RootState, companyIds: number[]) => {
  // Map over IDs, fetch each entity, and filter out any undefined values
  return companyIds.map(id => state.companies.entities[id]).filter(Boolean);
};

Then use it in your component at the top level:

const companyIds = useSelector(state => state.companyPages.entities[pageNumber]?.companyIds || []);
const companies = useSelector(state => selectCompaniesByIds(state, companyIds));

Note the optional chaining (?.) and fallback to an empty array for companyIds—this handles cases where pageNumber doesn't exist in companyPages.entities.

2. Memoized Selector (Performance Optimized)

If your component re-renders frequently or you're working with large ID arrays, use Redux Toolkit's built-in integration with Reselect to create a memoized selector. This ensures the selector only recalculates when either the companies.entities or companyIds array changes, avoiding unnecessary re-renders.

First, create the memoized selector:

import { createSelector } from '@reduxjs/toolkit';
import { RootState } from '../path/to/your/store';

// Create a memoized selector that depends on companies entities and the ID array
const selectCompaniesByIds = createSelector(
  // Input selectors: get the raw entities and the ID array
  [
    (state: RootState) => state.companies.entities,
    (_state: RootState, companyIds: number[]) => companyIds
  ],
  // Result function: compute the final array of companies
  (entities, companyIds) => {
    return companyIds.map(id => entities[id]).filter(Boolean);
  }
);

Then use it in your component just like the basic version:

const companyIds = useSelector(state => state.companyPages.entities[pageNumber]?.companyIds || []);
const companies = useSelector(state => selectCompaniesByIds(state, companyIds));

Bonus: Leverage Entity Adapter Selectors

Since you're using createEntityAdapter for your slices, you can also use the built-in selectById selector alongside createSelector for consistency:

import { createSelector } from '@reduxjs/toolkit';
import { RootState } from '../path/to/your/store';
import { companyAdapter } from '../path/to/companySlice';

// Get the built-in selectById from your company adapter
const { selectById } = companyAdapter.getSelectors((state: RootState) => state.companies);

const selectCompaniesByIds = createSelector(
  [
    (state: RootState) => state,
    (_state: RootState, companyIds: number[]) => companyIds
  ],
  (state, companyIds) => {
    return companyIds.map(id => selectById(state, id)).filter(Boolean);
  }
);

This keeps your code aligned with Redux Toolkit's entity patterns.

Key Takeaways

  • Never call hooks like useSelector inside loops or nested functions—stick to the top level of your component.
  • Fetch all required entities in a single useSelector call using a custom selector.
  • Use memoized selectors with createSelector to optimize performance for frequent re-renders or large datasets.

内容的提问来源于stack exchange,提问作者Dima Kambalin

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.29 22:32:34