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

如何在NgRx中无需额外属性过滤Observable任务集合?

用NgRx Store实现Todo列表筛选(无需维护组件额外属性)

直接上解决方案:核心是用RxJS的combineLatest组合任务集合与筛选条件的Observable,实时派生筛选后的结果列表,全程用响应式方式处理,不用手动订阅后在组件中维护额外属性。

步骤拆解

1. 确保Store状态结构正确

假设你的Model、Actions、Reducer已完成基础定义:

  • Todo接口包含id、title、completed字段
  • 筛选条件为TodoFilter类型,可选值'ALL' | 'ACTIVE' | 'COMPLETED'
  • Reducer维护的状态包含todos: Todo[]和currentFilter: TodoFilter两个核心字段

2. 组件中直接派生筛选后的Observable

无需在组件内订阅filter$存储变量,直接创建filteredTodos$来实时计算筛选结果:

import { Component } from '@angular/core';
import { Store } from '@ngrx/store';
import { combineLatest } from 'rxjs';
import { map } from 'rxjs/operators';
import { selectTodos, selectCurrentFilter } from './store/todo.selectors';
import { TodoFilter } from './models/todo.model';

@Component({
  selector: 'app-todo-list',
  templateUrl: './todo-list.component.html'
})
export class TodoListComponent {
  // 从Store获取原始数据的Observable
  todos$ = this.store.select(selectTodos);
  filter$ = this.store.select(selectCurrentFilter);

  // 组合两个流,实时计算筛选后的任务列表
  filteredTodos$ = combineLatest([this.todos$, this.filter$]).pipe(
    map(([todos, filter]) => {
      switch (filter) {
        case 'ACTIVE':
          return todos.filter(t => !t.completed);
        case 'COMPLETED':
          return todos.filter(t => t.completed);
        default:
          return todos;
      }
    })
  );

  constructor(private store: Store) {}

  // 切换筛选条件,dispatch对应Action
  setFilter(filter: TodoFilter) {
    this.store.dispatch(setTodoFilter({ filter }));
  }

  // 任务状态切换、删除等操作方法
  toggleTodo(id: number) {
    this.store.dispatch(toggleTodo({ id }));
  }

  deleteTodo(id: number) {
    this.store.dispatch(deleteTodo({ id }));
  }
}

3. 模板用async管道直接绑定

模板中无需处理组件属性,直接用async管道订阅filteredTodos$,筛选按钮也通过filter$ | async判断激活状态:

<ul class="todo-list">
  <li *ngFor="let todo of filteredTodos$ | async" 
      [class.completed]="todo.completed">
    <input type="checkbox" 
           [checked]="todo.completed" 
           (change)="toggleTodo(todo.id)">
    <span>{{ todo.title }}</span>
    <button (click)="deleteTodo(todo.id)">×</button>
  </li>
</ul>

<div class="filters">
  <button (click)="setFilter('ALL')" 
          [class.selected]="(filter$ | async) === 'ALL'">全部</button>
  <button (click)="setFilter('ACTIVE')" 
          [class.selected]="(filter$ | async) === 'ACTIVE'">未完成</button>
  <button (click)="setFilter('COMPLETED')" 
          [class.selected]="(filter$ | async) === 'COMPLETED'">已完成</button>
</div>

4. 补充Store选择器(可选但推荐)

为了更优雅地从Store中提取状态,定义对应的选择器:

// todo.selectors.ts
import { createFeatureSelector, createSelector } from '@ngrx/store';
import { TodoState } from './todo.reducer';

// 获取整个Todo模块的状态
const selectTodoState = createFeatureSelector<TodoState>('todos');

// 获取任务列表
export const selectTodos = createSelector(
  selectTodoState,
  state => state.todos
);

// 获取当前筛选条件
export const selectCurrentFilter = createSelector(
  selectTodoState,
  state => state.currentFilter
);

方案优势

  • 无需在组件中维护额外的currentFilter或filteredTodos变量,简化组件逻辑
  • async管道自动管理订阅生命周期,避免手动取消订阅导致的内存泄漏
  • 完全遵循NgRx响应式思路,状态全由Store统一管理,组件仅负责展示和触发动作

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.05 03:30:58