magic starSummarize by Aili

Angular Signals, Reactive Context, and Dynamic Dependency Tracking

๐ŸŒˆ Abstract

The article discusses the concept of "reactive context" and dependency tracking in Angular Signals, and how to avoid related bugs.

๐Ÿ™‹ Q&A

[01] Dependency Tracking

1. What is the "dependency graph" in Angular Signals?

  • The dependency graph is a graph of nodes, where each node implements the ReactiveNode interface.
  • Producers are nodes that contain values and notify about new values.
  • Consumers are nodes that read produced values.
  • Signals are producers, computed() is both producer and consumer, effect() is a consumer, and templates are consumers.

2. How does automatic dependency tracking work in Angular Signals?

  • There is a global variable called activeConsumer.
  • When computed(), effect(), or a template is being executed:
    • They read the value of activeConsumer to remember the previous consumer.
    • They register themselves as the activeConsumer.
    • They run their function or execute the template (potentially reading some signals).
    • They register the previous consumer (from step 1) as the activeConsumer.
  • When a producer is read, it retrieves the value of activeConsumer and includes this active consumer in the list of consumers dependent on the signal.
  • When a signal is updated, it sends a notification to every consumer from its list.

3. What is the importance of understanding dependency tracking in Angular Signals?

  • Consumers (computed(), effect(), templates) don't need to worry about adding the signals they read to the list of dependencies. Signals will do it themselves using the activeConsumer variable.
  • This means that no matter how deep in the function call chain a signal is read, it will be added to the list of dependencies.
  • Understanding this behavior is important to avoid bugs related to unintended dependencies or lack of dependencies.

[02] Reactive Context

1. What is the "reactive context" in Angular Signals?

  • The reactive context is related to the activeConsumer variable.
  • When activeConsumer is not null, signals that are read will add the activeConsumer to the list of consumers.
  • If a reactive node is read while activeConsumer is empty, it will not create any new link in the reactive nodes dependency graph.

2. How can the reactive context be unintentionally leaked?

  • Leaking the reactive context can happen in various ways, such as:
    • Creating an instance of a class that reads some signals.
    • Calling a function that calls another function, which reads a signal.
    • Emitting a new value to an observable.
  • This can lead to unexpected behavior, where signals that should not be dependencies end up triggering recomputations.

3. How can the use of untracked() help manage the reactive context?

  • untracked() can be used to control which dependencies are tracked by a computed() or effect().
  • If you don't want a function called within a computed() or effect() to trigger a recomputation when its value changes, you can wrap it with untracked().
  • This helps prevent unintended dependencies and leaks in the reactive context.
Shared by Daniel Chen ยท
ยฉ 2024 NewMotor Inc.