NgRx状态管理技能Skill ngrx

本技能提供在Angular应用中实现NgRx状态管理的专家级指导,涵盖存储配置、动作、减速器、选择器、效果、实体适配器和组件存储等核心概念。适用于构建可扩展、可维护的企业级前端应用,处理复杂数据流和异步操作。关键词:NgRx, Angular, 状态管理, 前端开发, 存储, 效果, 实体适配器, 组件存储, 选择器, 异步操作, 企业级应用。

前端开发 0 次安装 0 次浏览 更新于 2/26/2026

名称: ngrx 描述: 用于Angular的NgRx状态管理,包括存储、效果、实体适配器、组件存储和选择器。 允许工具: 读取、写入、编辑、Bash、Glob、Grep

NgRx 技能

为Angular应用程序实现NgRx状态管理的专家级协助。

能力

  • 配置具有功能状态的NgRx存储
  • 创建动作、减速器和选择器
  • 实现副作用的效果
  • 为集合使用实体适配器
  • 为本地状态应用组件存储
  • 设置NgRx DevTools集成

使用场景

在以下情况下调用此技能:

  • 实现集中式状态管理
  • 处理复杂的异步工作流
  • 管理规范化的实体集合
  • 使用DevTools调试状态变更
  • 扩展Angular应用程序状态

输入参数

参数 类型 是否必需 描述
功能名称 字符串 功能状态名称
实体适配器 布尔值 使用实体适配器
效果 数组 要创建的效果
组件存储 布尔值 使用组件存储

配置示例

{
  "功能名称": "用户",
  "实体适配器": true,
  "效果": ["加载用户", "创建用户", "更新用户"],
  "组件存储": false
}

NgRx 模式

动作

// store/users/users.actions.ts
import { createActionGroup, emptyProps, props } from '@ngrx/store';

export const UsersActions = createActionGroup({
  source: 'Users',
  events: {
    '加载用户': emptyProps(),
    '加载用户成功': props<{ users: User[] }>(),
    '加载用户失败': props<{ error: string }>(),

    '创建用户': props<{ user: CreateUserDto }>(),
    '创建用户成功': props<{ user: User }>(),
    '创建用户失败': props<{ error: string }>(),

    '更新用户': props<{ id: string; changes: Partial<User> }>(),
    '更新用户成功': props<{ user: User }>(),
    '更新用户失败': props<{ error: string }>(),

    '删除用户': props<{ id: string }>(),
    '删除用户成功': props<{ id: string }>(),
    '删除用户失败': props<{ error: string }>(),

    '选择用户': props<{ id: string | null }>(),
  },
});

使用实体适配器的减速器

// store/users/users.reducer.ts
import { createReducer, on } from '@ngrx/store';
import { createEntityAdapter, EntityState } from '@ngrx/entity';
import { UsersActions } from './users.actions';

export interface User {
  id: string;
  name: string;
  email: string;
}

export interface UsersState extends EntityState<User> {
  selectedId: string | null;
  loading: boolean;
  error: string | null;
}

export const usersAdapter = createEntityAdapter<User>({
  selectId: (user) => user.id,
  sortComparer: (a, b) => a.name.localeCompare(b.name),
});

const initialState: UsersState = usersAdapter.getInitialState({
  selectedId: null,
  loading: false,
  error: null,
});

export const usersReducer = createReducer(
  initialState,

  on(UsersActions.loadUsers, (state) => ({
    ...state,
    loading: true,
    error: null,
  })),

  on(UsersActions.loadUsersSuccess, (state, { users }) =>
    usersAdapter.setAll(users, { ...state, loading: false })
  ),

  on(UsersActions.loadUsersFailure, (state, { error }) => ({
    ...state,
    loading: false,
    error,
  })),

  on(UsersActions.createUserSuccess, (state, { user }) =>
    usersAdapter.addOne(user, state)
  ),

  on(UsersActions.updateUserSuccess, (state, { user }) =>
    usersAdapter.updateOne({ id: user.id, changes: user }, state)
  ),

  on(UsersActions.deleteUserSuccess, (state, { id }) =>
    usersAdapter.removeOne(id, state)
  ),

  on(UsersActions.selectUser, (state, { id }) => ({
    ...state,
    selectedId: id,
  }))
);

选择器

// store/users/users.selectors.ts
import { createFeatureSelector, createSelector } from '@ngrx/store';
import { usersAdapter, UsersState } from './users.reducer';

export const selectUsersState = createFeatureSelector<UsersState>('users');

const { selectAll, selectEntities, selectIds, selectTotal } =
  usersAdapter.getSelectors();

export const selectAllUsers = createSelector(selectUsersState, selectAll);

export const selectUserEntities = createSelector(
  selectUsersState,
  selectEntities
);

export const selectUsersLoading = createSelector(
  selectUsersState,
  (state) => state.loading
);

export const selectUsersError = createSelector(
  selectUsersState,
  (state) => state.error
);

export const selectSelectedUserId = createSelector(
  selectUsersState,
  (state) => state.selectedId
);

export const selectSelectedUser = createSelector(
  selectUserEntities,
  selectSelectedUserId,
  (entities, selectedId) => (selectedId ? entities[selectedId] : null)
);

export const selectUsersCount = createSelector(selectUsersState, selectTotal);

效果

// store/users/users.effects.ts
import { Injectable, inject } from '@angular/core';
import { Actions, createEffect, ofType } from '@ngrx/effects';
import { catchError, map, mergeMap, switchMap, of } from 'rxjs';
import { UsersActions } from './users.actions';
import { UsersService } from '../../services/users.service';

@Injectable()
export class UsersEffects {
  private actions$ = inject(Actions);
  private usersService = inject(UsersService);

  loadUsers$ = createEffect(() =>
    this.actions$.pipe(
      ofType(UsersActions.loadUsers),
      switchMap(() =>
        this.usersService.getAll().pipe(
          map((users) => UsersActions.loadUsersSuccess({ users })),
          catchError((error) =>
            of(UsersActions.loadUsersFailure({ error: error.message }))
          )
        )
      )
    )
  );

  createUser$ = createEffect(() =>
    this.actions$.pipe(
      ofType(UsersActions.createUser),
      mergeMap(({ user }) =>
        this.usersService.create(user).pipe(
          map((user) => UsersActions.createUserSuccess({ user })),
          catchError((error) =>
            of(UsersActions.createUserFailure({ error: error.message }))
          )
        )
      )
    )
  );

  updateUser$ = createEffect(() =>
    this.actions$.pipe(
      ofType(UsersActions.updateUser),
      mergeMap(({ id, changes }) =>
        this.usersService.update(id, changes).pipe(
          map((user) => UsersActions.updateUserSuccess({ user })),
          catchError((error) =>
            of(UsersActions.updateUserFailure({ error: error.message }))
          )
        )
      )
    )
  );

  deleteUser$ = createEffect(() =>
    this.actions$.pipe(
      ofType(UsersActions.deleteUser),
      mergeMap(({ id }) =>
        this.usersService.delete(id).pipe(
          map(() => UsersActions.deleteUserSuccess({ id })),
          catchError((error) =>
            of(UsersActions.deleteUserFailure({ error: error.message }))
          )
        )
      )
    )
  );
}

组件存储(本地状态)

// components/user-list/user-list.store.ts
import { Injectable } from '@angular/core';
import { ComponentStore } from '@ngrx/component-store';
import { switchMap, tap, catchError, EMPTY } from 'rxjs';

interface UserListState {
  users: User[];
  loading: boolean;
  filter: string;
}

@Injectable()
export class UserListStore extends ComponentStore<UserListState> {
  constructor(private usersService: UsersService) {
    super({
      users: [],
      loading: false,
      filter: '',
    });
  }

  // 选择器
  readonly users$ = this.select((state) => state.users);
  readonly loading$ = this.select((state) => state.loading);
  readonly filter$ = this.select((state) => state.filter);

  readonly filteredUsers$ = this.select(
    this.users$,
    this.filter$,
    (users, filter) =>
      users.filter((u) => u.name.toLowerCase().includes(filter.toLowerCase()))
  );

  // 更新器
  readonly setFilter = this.updater((state, filter: string) => ({
    ...state,
    filter,
  }));

  // 效果
  readonly loadUsers = this.effect((trigger$) =>
    trigger$.pipe(
      tap(() => this.patchState({ loading: true })),
      switchMap(() =>
        this.usersService.getAll().pipe(
          tap((users) => this.patchState({ users, loading: false })),
          catchError(() => {
            this.patchState({ loading: false });
            return EMPTY;
          })
        )
      )
    )
  );
}

存储设置

// app.config.ts
import { ApplicationConfig } from '@angular/core';
import { provideStore } from '@ngrx/store';
import { provideEffects } from '@ngrx/effects';
import { provideStoreDevtools } from '@ngrx/store-devtools';
import { usersReducer } from './store/users/users.reducer';
import { UsersEffects } from './store/users/users.effects';

export const appConfig: ApplicationConfig = {
  providers: [
    provideStore({
      users: usersReducer,
    }),
    provideEffects(UsersEffects),
    provideStoreDevtools({
      maxAge: 25,
      logOnly: false,
    }),
  ],
};

最佳实践

  • 使用 createActionGroup 创建相关动作
  • 利用实体适配器处理集合
  • 保持效果专注于单一职责
  • 为本地状态使用组件存储
  • 创建细粒度选择器以提升性能

目标流程

  • angular-enterprise-development
  • state-management-setup
  • complex-data-flows
  • enterprise-architecture