How to use selectors in NgRx
NgRx selectors are pure functions that extract and compute derived state from the store with automatic memoization for performance. As the creator of CoreUI with 12 years of Angular development experience, I’ve built complex selector trees in enterprise applications that efficiently compute derived data for millions of users while preventing unnecessary component re-renders.
The most effective approach uses createSelector with memoization for computed state.
Basic Feature Selector
import { createFeatureSelector } from '@ngrx/store'
export interface AppState {
users: UserState
products: ProductState
}
export interface UserState {
users: User[]
loading: boolean
selectedId: number | null
}
// Select the feature state
export const selectUserState = createFeatureSelector<UserState>('users')
Simple Property Selectors
import { createSelector } from '@ngrx/store'
// Select specific properties from feature state
export const selectAllUsers = createSelector(
selectUserState,
(state: UserState) => state.users
)
export const selectUsersLoading = createSelector(
selectUserState,
(state: UserState) => state.loading
)
export const selectSelectedUserId = createSelector(
selectUserState,
(state: UserState) => state.selectedId
)
Computed Selectors
// Select active users (computed from all users)
export const selectActiveUsers = createSelector(
selectAllUsers,
(users: User[]) => users.filter(user => user.active)
)
// Select user count
export const selectUserCount = createSelector(
selectAllUsers,
(users: User[]) => users.length
)
// Select users by role
export const selectAdminUsers = createSelector(
selectAllUsers,
(users: User[]) => users.filter(user => user.role === 'admin')
)
Parameterized Selectors
// Select user by ID
export const selectUserById = (userId: number) =>
createSelector(
selectAllUsers,
(users: User[]) => users.find(user => user.id === userId)
)
// Usage in component
@Component({
selector: 'app-user-detail',
template: `<div>{{ user$ | async | json }}</div>`
})
export class UserDetailComponent implements OnInit {
user$ = this.store.select(selectUserById(this.userId))
constructor(
private store: Store,
private route: ActivatedRoute
) {}
ngOnInit() {
this.userId = +this.route.snapshot.paramMap.get('id')
}
}
Combining Multiple Selectors
// Combine selectors from different features
export const selectProductState = createFeatureSelector<ProductState>('products')
export const selectAllProducts = createSelector(
selectProductState,
(state: ProductState) => state.products
)
export const selectCartState = createFeatureSelector<CartState>('cart')
export const selectCartItems = createSelector(
selectCartState,
(state: CartState) => state.items
)
// Combine data from multiple features
export const selectCartWithProducts = createSelector(
selectCartItems,
selectAllProducts,
(cartItems, products) => {
return cartItems.map(item => ({
...item,
product: products.find(p => p.id === item.productId)
}))
}
)
// Calculate cart total
export const selectCartTotal = createSelector(
selectCartWithProducts,
(items) => {
return items.reduce((total, item) => {
return total + (item.product?.price || 0) * item.quantity
}, 0)
}
)
Selector Composition
// Build complex selectors from simpler ones
export const selectUserViewModel = createSelector(
selectAllUsers,
selectUsersLoading,
selectSelectedUserId,
(users, loading, selectedId) => ({
users,
loading,
selectedUser: users.find(u => u.id === selectedId),
totalCount: users.length,
activeCount: users.filter(u => u.active).length
})
)
Using Selectors in Components
import { Component, OnInit } from '@angular/core'
import { Store } from '@ngrx/store'
import { Observable } from 'rxjs'
import { selectAllUsers, selectUsersLoading } from './store/user.selectors'
@Component({
selector: 'app-user-list',
template: `
<div *ngIf="loading$ | async">Loading...</div>
<ul>
<li *ngFor="let user of users$ | async">
{{ user.name }}
</li>
</ul>
`
})
export class UserListComponent implements OnInit {
users$: Observable<User[]>
loading$: Observable<boolean>
constructor(private store: Store) {}
ngOnInit() {
this.users$ = this.store.select(selectAllUsers)
this.loading$ = this.store.select(selectUsersLoading)
}
}
Selector with Props
// Modern approach with props
export const selectUsersByRole = createSelector(
selectAllUsers,
(users: User[], props: { role: string }) => {
return users.filter(user => user.role === props.role)
}
)
// Usage in component
@Component({
selector: 'app-role-users',
template: `<div>{{ users$ | async | json }}</div>`
})
export class RoleUsersComponent {
@Input() role: string
users$ = this.store.select(selectUsersByRole, { role: this.role })
constructor(private store: Store) {}
}
Selector Memoization Benefits
// Selectors are memoized - only recompute when inputs change
export const selectExpensiveComputation = createSelector(
selectAllUsers,
(users: User[]) => {
console.log('Computing expensive result...')
// This only runs when users array changes
return users.map(user => ({
...user,
fullName: `${user.firstName} ${user.lastName}`,
age: calculateAge(user.birthDate)
}))
}
)
// Multiple subscriptions share the same memoized result
@Component({
selector: 'app-dashboard',
template: `
<app-user-stats [data]="computed$ | async"></app-user-stats>
<app-user-chart [data]="computed$ | async"></app-user-chart>
`
})
export class DashboardComponent {
// Both subscriptions use the same memoized result
computed$ = this.store.select(selectExpensiveComputation)
constructor(private store: Store) {}
}
Selector Testing
import { selectAllUsers, selectActiveUsers } from './user.selectors'
describe('User Selectors', () => {
const mockState: UserState = {
users: [
{ id: 1, name: 'John', active: true },
{ id: 2, name: 'Jane', active: false }
],
loading: false,
selectedId: null
}
it('should select all users', () => {
const result = selectAllUsers.projector(mockState)
expect(result.length).toBe(2)
})
it('should select only active users', () => {
const allUsers = selectAllUsers.projector(mockState)
const result = selectActiveUsers.projector(allUsers)
expect(result.length).toBe(1)
expect(result[0].name).toBe('John')
})
})
Best Practice Note
This is how we structure selectors in all CoreUI Angular projects for efficient state management. NgRx selectors provide automatic memoization that prevents unnecessary computations and component re-renders. Always use createSelector for derived state, compose simple selectors into complex ones, and leverage memoization to optimize performance in large applications.
For production applications, consider using CoreUI’s Angular Admin Template which includes pre-configured NgRx with selector patterns.
Related Articles
For complete NgRx implementation, check out how to use NgRx Store in Angular and how to use reducers in NgRx.



