NgRx Store中select与map行为差异:为何map触发多次订阅回调?
问题描述
使用NgRx Store的EntityAdapter获取客户列表时,两种写法触发订阅回调的次数完全不同:
第一种写法(使用select操作符)仅触发一次:
this.store.pipe(select(this.selectCustomersFunction)) .subscribe(items => { console.log('======> Select Customers Function Called'); // 仅执行一次 });
第二种写法(使用map操作符)会多次触发:
this.store.pipe( map((state: CustomerState) => this.selectCustomersFunction(state)) ) .subscribe(items => { console.log('======> Select Items Function Called'); // 执行多次 });
相关EntityAdapter代码:
export const selectAllCustomers = createSelector( fromPortal.getCustomerEntitiesState, fromCustomer.selectAllCustomers ); const { selectIds, selectEntities, selectAll, selectTotal, } = adapter.getSelectors(); // 选择客户数组 export const selectAllCustomers = selectAll;
原因分析
NgRx
select操作符的记忆化特性:你定义的selectAllCustomers是通过createSelector创建的记忆化选择器。当使用store.pipe(select(selector))时,NgRx会自动利用选择器的记忆化逻辑——只有当选择器依赖的状态片段(也就是客户相关的状态)发生变化时,才会重新计算结果并推送给订阅者。如果客户列表没有更新,订阅只会在初始时执行一次。map操作符的无差别触发逻辑:用map直接调用选择器函数时,相当于监听整个store的全局状态。只要store中任意部分的状态发生变化(哪怕和客户列表完全无关),map都会执行选择器函数并返回结果,进而触发订阅回调。这就导致了回调被多次执行。
简单总结:select+记忆化选择器只关注目标状态的变化,而map会响应全局所有状态的更新。
内容的提问来源于stack exchange,提问作者wonderful world
相关产品推荐
相关产品推荐

