如何在NgRx Selectors中访问前状态与当前状态?
在NgRx Selectors中访问前后状态的实现方案
默认情况下,NgRx的createSelector只能基于当前状态派生数据,没法直接获取前状态。不过你可以通过两种实用方式实现需求:
方法1:在State中维护前状态副本
把前状态的副本存在store的state结构里,这样就能通过selector同时拿到当前和前状态。
具体示例:
- 定义包含前状态的State结构
interface CounterState { currentValue: number; previousValue: number; // 专门存前一次的状态值 } const initialState: CounterState = { currentValue: 0, previousValue: 0, };
- 在Reducer中同步更新前状态
每次状态变更时,先把当前值转移到previousValue,再更新currentValue:
export function counterReducer(state = initialState, action: CounterActions): CounterState { switch (action.type) { case '[Counter] Increment': return { ...state, previousValue: state.currentValue, currentValue: state.currentValue + 1, }; // 其他action(比如Decrement)同理处理 default: return state; } }
- 创建Selector提取前后状态
用createSelector直接从state中取出两个值并返回:
import { createSelector } from '@ngrx/store'; const selectCounterState = (state: AppState) => state.counter; export const selectCounterWithPrevious = createSelector( selectCounterState, (counterState) => ({ current: counterState.currentValue, previous: counterState.previousValue, }) );
- 在组件中使用
this.store.select(selectCounterWithPrevious).subscribe(({ current, previous }) => { console.log(`当前值: ${current}, 前一次值: ${previous}`); // 这里可以执行你的推导逻辑,比如计算差值 const changeAmount = current - previous; });
方法2:用RxJS的pairwise()操作符
不需要修改state结构,直接在订阅selector时通过pairwise()获取连续的两次状态值(前一次+当前)。
具体示例:
- 先创建常规Selector获取当前状态
const selectCurrentCounter = createSelector( selectCounterState, (counterState) => counterState.currentValue );
- 在组件中通过
pairwise()处理
import { pairwise } from 'rxjs/operators'; this.store.select(selectCurrentCounter) .pipe(pairwise()) // 每次发射一个数组:[前一次状态, 当前状态] .subscribe(([previous, current]) => { console.log(`前一次值: ${previous}, 当前值: ${current}`); // 执行推导逻辑,比如判断数值变化方向 const isIncreased = current > previous; });
补充:处理初始状态
pairwise()需要至少两次状态发射才会输出结果,如果想第一次状态变更就对比初始值,可以用startWith()补充初始值:
import { pairwise, startWith } from 'rxjs/operators'; this.store.select(selectCurrentCounter) .pipe( startWith(initialState.currentValue), // 把初始值作为第一个"前状态" pairwise() ) .subscribe(([previous, current]) => { // 第一次回调时,previous是初始值,current是第一次变更后的值 });
关于Factory Method
NgRx没有专门提供直接获取前后状态的工厂方法,上述两种是最常用的实现方式。如果需要复用逻辑,你可以自己封装一个高阶函数:
import { Observable } from 'rxjs'; import { pairwise, startWith, map } from 'rxjs/operators'; export function withPrevious<T>(source$: Observable<T>, initialValue: T): Observable<{ previous: T; current: T }> { return source$.pipe( startWith(initialValue), pairwise(), map(([previous, current]) => ({ previous, current })) ); } // 使用方式 const counterWithPrevious$ = withPrevious(this.store.select(selectCurrentCounter), initialState.currentValue); counterWithPrevious$.subscribe(data => { /* 你的处理逻辑 */ });
内容的提问来源于stack exchange,提问作者aravind ks
相关产品推荐
相关产品推荐

