You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

NGrx状态更新时所有Observable是否触发?含Entity行为疑问

NgRx State Updates, Observable Triggers, and State Structure Best Practices

Great question—this is a common point of confusion when working with immutable state in NgRx, especially when debating state structure. Let’s break this down step by step.

Core Question: Do All Observables Trigger on State Updates?

First, let’s confirm the basics: NgRx state is immutable, so every update creates a new root state object. But not all observables will emit a new value—it depends on how you select state and whether you use memoized selectors.

Using your example state:

interface State {
  backendState: BackendData;
  frontendState: FrontendState;
}

When you update frontendState and generate a new root state:

  • Subscriptions to the full root state (e.g., store.select(state => state)): Will trigger, since the root state reference is entirely new.
  • Subscriptions to frontendState:
    • Basic projection (e.g., store.select(state => state.frontendState)): Will trigger, because the new root state runs the projection, which returns the new frontendState reference.
    • Memoized selector (created with createSelector): Will also trigger, since the input slice (frontendState) has changed.
  • Subscriptions to backendState:
    • Basic projection: Won’t trigger. NgRx’s select operator uses distinctUntilChanged under the hood, which compares values by reference. Since backendState hasn’t changed (same reference), the observable filters out the duplicate value.
    • Memoized selector: Won’t trigger either. createSelector caches results and only recalculates when its input selectors return new values. Since backendState is unchanged, the selector returns the cached result, so no emission occurs.

Flat vs. Nested State: Is There a Performance Difference?

Your colleagues’ preference for flat state (using string IDs and mappings) likely stems from a misunderstanding of how memoized selectors work. Here’s the reality:

  • Nested state doesn’t cause unnecessary emissions if you use memoized selectors correctly. Only the slices of state you care about will trigger their observables when changed—regardless of whether the state is nested or flat.
  • Flat state can help with complex, cross-cutting state, but it’s not inherently more performant. Nested state often leads to cleaner, more maintainable code by grouping related state together (e.g., separating backendState and frontendState makes it clear which parts relate to backend vs. frontend logic).
  • The performance gain from flat state is negligible compared to the benefits of using memoized selectors. Don’t sacrifice code clarity for a hypothetical performance boost.

How Does NgRx Entity Behave?

NgRx Entity uses a structured state format for list data:

interface EntityState<T> {
  ids: string[];
  entities: { [id: string]: T };
}

When you update an entity (e.g., with updateOne):

  • A new entities object is created (immutability requires replacing objects instead of mutating them), but the ids array keeps its original reference if no entities were added or removed.
  • Memoized selectors for entities (like selectEntities) will emit a new value because the entities reference changed.
  • Selectors for ids (like selectIds) won’t emit, since the array reference is unchanged.
  • NgRx Entity’s built-in selectors are already memoized, so you get efficient state selection out of the box—no need to roll your own ID-based mappings.

Best Practices

  • Always use memoized selectors (createSelector) instead of basic projections. They prevent unnecessary emissions and make state selection more efficient, regardless of state structure.
  • Organize state by logical concern first. Group related state into nested slices if it makes the code more readable—don’t flatten just for the sake of it.
  • Use NgRx Entity for list data instead of manual ID-based mappings. It provides optimized CRUD reducers and selectors, reducing boilerplate and ensuring consistent, efficient state updates.
  • Avoid subscribing to the entire store. Only select the specific slices of state your component needs—this minimizes the amount of data flowing through your observables.

内容的提问来源于stack exchange,提问作者SchreiberLex

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.21 03:52:01