Angular 16中NgRx选择器结合计算信号的正确用法及逻辑位置
Angular 16 Signals 替代 NgRx Selectors 的正确实现与性能分析
场景背景
我正在使用Angular 16并刚开始使用Signals,它们让NgRx的使用体验更佳。过渡过程中,遇到可抽象为以下场景的问题:
原来使用NgRx Selectors的实现代码:
const state = { someArray: [1, 5, 7] } export const selectArray = createSelector( state, (state) => state.someArray ); export const selectFirst = createSelector( selectArray, (someArray) => someArray[0] ); export const selectLast = createSelector( selectArray, (someArray) => someArray[state.someArray.length-1] ); export const selectLastMinusFirst = createSelector( [selectFirst, selectLast], (first, last) => last - first );
现在尝试用Signals在组件中重写,有两种写法:
写法一:计算信号(computed)
const someArray: Signal<number[]> = this.store.selectSignal(Selectors.SelectArray) const first: Signal<number> = computed(() => someArray()[0]); const last: Signal<number> = computed(() => someArray()[state.someArray.length-1]); const lastMinusFirst: Signal<number> = computed(() => last() - first());
写法二:effect实现
let first = 0; let last = 0; let lastMinusFirst = 0; const someArray: Signal<number[]> = this.store.selectSignal(Selectors.SelectArray) constructor() { effect(() => { if(someArray().length) { this.first = someArray()[0]; this.last = someArray()[someArray().length - 1]; this.lastMinusFirst = this.last - this.first; } }); }
问题
请问正确的实现方式是什么?正如官方文档所述,计算信号因懒加载和缓存机制是否更高效?
解答
正确实现方式
优先选择**计算信号(computed)**的写法,同时需要修正代码中的错误:原写法里的last信号误用了外部的state变量,应该直接使用someArray()的长度来获取最后一项。修正后的代码如下:
const someArray: Signal<number[]> = this.store.selectSignal(Selectors.SelectArray); const first: Signal<number> = computed(() => someArray()[0]); const last: Signal<number> = computed(() => someArray()[someArray().length - 1]); const lastMinusFirst: Signal<number> = computed(() => last() - first());
而effect的写法不适合这个场景,原因如下:
effect的设计初衷是处理副作用操作(比如DOM修改、API请求、日志输出等),并非用于派生状态。- 手动维护
first、last这类变量会增加状态同步的复杂度,容易出现不一致的情况,远不如计算信号自动同步依赖的方式可靠简洁。
计算信号的性能优势
计算信号确实比effect写法更高效,核心得益于它的懒加载和缓存机制:
- 懒加载:计算信号只有在被订阅(比如在模板中使用、被其他计算信号或effect引用)时,才会执行计算逻辑,避免无意义的资源消耗。
- 缓存机制:只有当它依赖的信号(此处为
someArray)发生变化时,计算信号才会重新计算并更新结果;如果依赖未变化,直接返回缓存的结果。而effect会在依赖每次变化时都执行内部逻辑,哪怕结果没有被使用,会造成不必要的计算浪费。
此外,计算信号的写法更贴合Signals的设计理念,状态派生逻辑清晰,无需手动维护状态同步,能有效减少出错概率。
内容的提问来源于stack exchange,提问作者sili3011
相关产品推荐
相关产品推荐

