如何在NgRx中从实体特性创建包含扩展状态的选择器?
selectAll Selector Got it, let's break this down. The built-in selectAll selector from NgRx Entity is designed to only return the raw entities stored in the entities property of your state—it doesn't automatically pick up any extra state properties you added when extending EntityState. That's totally expected behavior, but we can fix this by creating custom selectors that combine the entities with your extended state.
First, let's recap your setup to make sure we're on the same page. I assume your state and adapter look something like this:
// Define your extended entity state export interface UxeGallery extends EntityState<Gallery> { // Your custom extended properties currentGalleryId: number | null; isLoading: boolean; fetchError: string | null; } // Create the entity adapter export const galleryAdapter = createEntityAdapter<Gallery>(); // Initialize state with your extended properties export const initialUxeGalleryState: UxeGallery = galleryAdapter.getInitialState({ currentGalleryId: null, isLoading: false, fetchError: null, }); // Feature selector for your state export const selectUxeGalleryState = createFeatureSelector<UxeGallery>('uxeGallery');
And you're currently using the adapter's built-in selectors like this:
const { selectAll } = galleryAdapter.getSelectors(selectUxeGalleryState); // In your component galleries$ = this.store.select(selectAll); // Only returns Gallery[], no extended state
Solution 1: Create a Custom Selector That Combines Entities + Extended State
If you often need to access both the entities and your extended state properties together, create a single selector that merges them:
import { createSelector } from '@ngrx/store'; // Get the built-in selectAll selector const { selectAll: selectAllGalleries } = galleryAdapter.getSelectors(selectUxeGalleryState); // Custom selector to return entities + extended state export const selectGalleryStateWithEntities = createSelector( selectUxeGalleryState, selectAllGalleries, (fullState, galleries) => ({ galleries, currentGalleryId: fullState.currentGalleryId, isLoading: fullState.isLoading, fetchError: fullState.fetchError, // Add any other extended properties you need here }) );
Then use this selector in your component:
// Now you get both entities and extended state in one observable galleryState$ = this.store.select(selectGalleryStateWithEntities); // In your template, you can access like: // <div *ngIf="galleryState$ | async as state"> // <p>Loading: {{ state.isLoading }}</p> // <div *ngFor="let gallery of state.galleries">{{ gallery.name }}</div> // </div>
Solution 2: Create Separate Selectors for Extended State Properties
If you only need to access individual extended properties alongside entities, you can create dedicated selectors for each custom state field and combine them in your component:
// Selectors for individual extended state properties export const selectGalleryLoading = createSelector( selectUxeGalleryState, state => state.isLoading ); export const selectCurrentGalleryId = createSelector( selectUxeGalleryState, state => state.currentGalleryId );
Then in your component, combine them with selectAll using combineLatest:
import { combineLatest } from 'rxjs'; import { map } from 'rxjs/operators'; galleries$ = this.store.select(selectAllGalleries); loading$ = this.store.select(selectGalleryLoading); // Combine into a single observable if needed galleryData$ = combineLatest([galleries$, loading$]).pipe( map(([galleries, isLoading]) => ({ galleries, isLoading })) );
Why This Works
The built-in selectAll selector from the entity adapter only looks at the entities and ids properties of your state (the core parts of EntityState). When you extend EntityState with custom properties, those live outside the core entity structure, so you need to explicitly include them in your custom selectors.
Choose the approach that fits your use case: the first method is great for when you regularly need the full state + entities together, while the second is more flexible for picking and choosing individual properties.
内容的提问来源于stack exchange,提问作者John Abraham

