Angular之store全局状态管理 浅学(二)

        在Angular之store浅学(一)中已经对store的相关概念和用法进行了比较全面的浅析,在本篇博文中我们将着重学习Store中的selector。

        在文章正式开始前,让我们先借鉴一下Angular 17+NGRX 状态管理大佬的分析图进行简单的 复习及预习:

 Store概念复习:
  1. 基本概念
    • Store: 是一个集中式的状态容器,它保存了应用程序的状态,并允许组件通过dispatch 方法发送操作(actions)来更改状态。
    • Actions: 是表示应用程序事件的对象,通常用于描述将要发生的事情。例如:{type: 'ADD_TODO', payload: {text:'Learn NgRx'}}。
    • Reducers: 是纯函数,定义了如何根据不同的 action 更新 state。
    • Selectors: 是纯函数,用于从 Store 中选择和派生特定的数据片段。
  2. 设置 Store
    • 定义 State: 定义一个接口来描述状态的形状。​​​​​​​

    • 创建 Actions: 定义不同的操作类型。

    • 创建 Reducers: 编写 reducer 函数来处理不同的 actions 并更新 state。

    • 创建 Selectors: 编写 selectors 来从 state 中选择特定的数据。

    • 使用 Store: 在组件中注入 Store 并使用它来分发 actions 或选择数据。

Selector 方法的触发时机

  Selector是用来从 Store 中获取状态的工具函数。它们会根据状态的变化来派发新的数据,但并不是立即触发的,而是有一些触发时机:

  1. 状态变化: 当 Store 中的状态通过 Reducer 更新时,所有依赖该状态的 selectors 都会重新计算。如果一个 selector 依赖于另一个 selector,并且后者的状态发生变化,那么前者也会重新计算。

  2. 组件订阅: 在组件中,通常通过select 方法来获取数据流。如果组件订阅了某个 selector,那么当 Store 中的状态发生变化并且 selector 重新计算时,组件会接收到新的值。

  3. Selector 缓存: NgRx 使用reselect 库提供的 memoization 功能来缓存 selector 的计算结果,只有当 selector 的输入发生变化时才会重新计算。这确保了性能优化。

        谈到selector的触发时机,那么就不得不提一下订阅store的时候不同的写法之间的稍许差异,就以上面第五点中的三种方法来看,具体的解析如下:

        示例的公共代码如下:

// state 中初始化了两个变量 a, b
export interface AppState {
    a: number;
    b: string;
}

export const initialState: AppState = {
    a: 1,
    b: 'madsion'
};


// reducer 函数
function myReducer(state = initialState, action: SomeAction): AppState {
  switch (action.type) {
    case 'MY_ACTION':
      // Just return the current state
      return state;
    // other cases
    default:
      return state;
  }
}
第一种订阅store的写法:
// selector 选择器中的代码
this.store.select(state => state).subscribe(state => {
  console.log(state); // Logging the value of `a`
});
默认行为
  • Selector 触发次数

    • this.store.select(state => state)是一个直接返回整个 state 的选择器。由于state 是整个应用程序的状态,每次 store 更新时,选择器函数都会被调用。
    • 每当有新的 action 被派发并处理完毕(即 reducer 执行并返回新的 state),this.store.select(state => state) 会检测到 state 的变化并发出新的值。如果 action 只是返回当前的 state(即不修改 state),状态实际上不会发生变化,但store.select 仍然会重新发出 state 作为新的值。因此,每个派发的 action 都会导致select函数触发。
  • console.log(state) 执行次数

    • 因为state => state返回的是整个state,每次 store 更新时这个选择器都会发出新的值,即(整个状态对象)被发送到subscribe函数中,因此每次 store 更新时,console.log(state)都会执行一次,即使你没有显式地修改state,只要有新的 action 触发,subscribe会响应每次state的发出console.log(state)都会执行。
总结
  1. Selector 函数触发次数:每次 store 更新时,无论状态是否实际发生变化,选择器都会触发,并发出当前的 state。
  2. console.log(state) 执行次数:每次 store 更新时(即每次有 action 被处理时),console.log(state)会执行一次。即使 action 不改变状态,这个日志输出也会因为选择器每次都发出新的 state 而被执行。
  3. 这种设置适用于需要监控整个 store 状态的情况。
第二种/第三种订阅store的写法:
​
// selector 选择器中的代码
this.store.select(state => state.a).subscribe(state => {
  console.log(state.a); // Logging the value of `a`
});

​
默认行为

Selector 触发次数

  • 在@ngrx/store中,默认情况下,select操作会根据选择器的输入进行 memoization。也就是说,如果选择器的输入值没有变化(例如,state.a 没有变化),selector的订阅不会触发新的通知。选择器会返回缓存的结果。
  • 如果你的 action 只是简单地返回当前的 state,没有对state.a 做出修改,那么state.a 在 store 中的值没有变化。因此,this.store.select(state => state.a) 不会重新发出值。

console.log(state.a) 执行次数

  • 如果state.a 没有变化,那么console.log(state.a)不会被执行,因为selector 没有发出新的值。
  • 如果state.a 发生了变化,console.log(state.a)会被执行一次,输出新值。
总结
  1. selector 函数的调用次数:不会多次触发selector 函数的调用,前提是state.a没有发生变化。选择器的 memoization 会防止不必要的重新计算。
  2. console.log(a) 的执行次数:console.log(state.a) 只会在state.a 变化时执MY_ACTION 没有改变state.a ,那么console.log(state.a) 不会执行。

Memoization机制

        在 Angular 的 @ngrx/store 中,memoization 是用于优化选择器(selectors)的性能的一种技术。选择器是从 store 中派生数据的函数,而 memoization 可以避免在相同的输入值下重新计算结果。通常,memoization 是启用的,帮助提高应用程序的性能。这意味着,选择器只会在其输入值发生变化时重新计算结果。如果选择器的输入值没有变化,它会返回缓存的结果。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值