Angular RXJS Store调度时变更检测及变更字段范围问询
Angular NgRx Store 变更检测相关问题解答
1. 当Store发出调度命令时,变更检测是如何工作的?
- 调用
store.dispatch()触发动作后,对应的reducer会接收当前状态和动作,生成全新的不可变状态对象(NgRx核心规则:状态不可修改,只能通过生成新对象更新)。 - Store本身是可观察对象,组件通过选择器(
createSelector)订阅状态的特定部分。 - 状态更新后,选择器会对比新旧状态的目标值:
- 普通选择器默认做引用对比,只要引用变化就会发出新值;
- 用
createSelector创建的memoized选择器会缓存结果,只有当输入参数的引用或实际值变化时,才会重新计算并推送新值。
- 组件通过
async管道或手动订阅选择器后,收到新值时会触发Angular变更检测,检查视图绑定的值是否变化,进而更新视图。
2. 在Angular NgRx Store中,调度Store更新时,哪些字段会被标记为已变更?是仅变更字段还是整个子树?
- NgRx基于不可变状态更新,reducer会替换整个受影响的状态子树(而非修改原对象的单个字段)。比如更新
state.shooters.selected时,state.shooters和selected都会是新对象。 - 变更检测的范围取决于组件订阅的选择器返回内容:
- 如果选择器返回整个子树(如
state.shooters),只要子树引用变化(哪怕内部仅一个字段修改),选择器就会推送新值,触发组件变更检测,此时视图中绑定的该子树所有字段都会被Angular检查。 - 如果选择器返回单个字段(如
state.shooters.selected.name),只有该字段实际值变化时,选择器才会推送新值,仅触发该字段相关的变更检测。
- 如果选择器返回整个子树(如
- memoized选择器可优化流程,仅在依赖的状态部分实际变化时推送新值,避免不必要的变更检测。
3. 执行this.store.dispatch(ShootManagementActions.setSelectedShooter({ shooter }))时,若shooter对象包含100个字段,从变更检测角度,是所有100个字段都被标记为“已变更”,还是仅标记实际与调度前不同的字段?
- 首先,reducer处理该动作时会生成全新的
selectedShooter对象(遵循不可变原则),因此该对象的引用与之前不同。 - 分两种情况:
- 若组件用普通选择器订阅整个
selectedShooter对象:
选择器会因引用变化推送新值,触发组件变更检测。此时Angular会对视图中绑定的所有shooter字段做浅对比——只有实际值变化的字段会被视为“已变更”并更新视图;未变化的字段虽会被检查,但不会触发视图更新。 - 若组件用自定义memoized选择器(比如添加字段级对比逻辑):
只有当shooter对象中存在实际值变化的字段时,选择器才会推送新值,此时变更检测仅针对变化字段对应的视图绑定。
- 若组件用普通选择器订阅整个
- 总结:Store不会主动“标记”字段变更,而是通过不可变状态更新触发选择器推送,Angular变更检测会自行检查每个绑定值的变化,最终只有实际变化的字段会触发视图更新。
内容的提问来源于stack exchange,提问作者Steve Geggie
相关产品推荐
相关产品推荐

