乐闻世界logo
搜索文章和话题

How does MobX's dependency tracking system work?

2月21日 15:45

MobX's dependency tracking system is its core mechanism, achieving efficient reactive updates through fine-grained tracking. Here's a detailed explanation of how MobX dependency tracking works:

Basic Principles of Dependency Tracking

MobX uses the Observer Pattern and Dependency Graph to implement dependency tracking. When an observable is accessed, MobX establishes dependency relationships; when an observable is modified, MobX notifies all observers that depend on it.

Core Components

1. Reaction

Reaction is the execution unit of dependency tracking, including:

  • autorun: Executes immediately and automatically re-executes when dependencies change
  • reaction: Provides more fine-grained control, allowing specification of tracking function and effect function
  • observer (React component): Wraps React components to make them responsive to state changes
  • computed: Computed values, which are also a special type of reaction

2. Derivation

Derivation represents calculations or side effects that depend on observables. Each derivation maintains a list of dependencies.

3. Atom

Atom is the smallest observable unit. Each observable object, array, Map, etc., is composed of multiple atoms.

Execution Flow of Dependency Tracking

1. Tracing Phase

When a reaction executes:

javascript
autorun(() => { console.log(store.count); // Access observable });

Execution steps:

  1. MobX marks the current reaction as "tracking"
  2. When accessing store.count, MobX records that this reaction depends on the count atom
  3. Continues execution, recording all accessed observables
  4. After execution completes, the reaction enters a "stable" state

2. Notification Phase

When an observable is modified:

javascript
runInAction(() => { store.count++; // Modify observable });

Execution steps:

  1. MobX detects that the count atom has been modified
  2. Finds all reactions that depend on count
  3. Marks these reactions as "stale"
  4. In the next event loop, re-executes these reactions

Structure of Dependency Graph

MobX maintains a bidirectional dependency graph:

  • Atom → Derivation: Each atom knows which derivations depend on it
  • Derivation → Atom: Each derivation knows which atoms it depends on

This bidirectional relationship allows MobX to efficiently perform dependency updates and cleanup.

Fine-grained Updates

MobX's dependency tracking is fine-grained, which means:

  • Only updates parts that truly need updating
  • Avoids unnecessary recalculations and re-renders
  • Automatically handles nested dependencies

Example:

javascript
class Store { @observable firstName = 'John'; @observable lastName = 'Doe'; @observable age = 30; @computed get fullName() { return `${this.firstName} ${this.lastName}`; } } const observerComponent = observer(() => { // Only depends on fullName, not on age return <div>{store.fullName}</div>; });

When age changes, the component won't re-render; only when firstName or lastName changes will it re-render.

Batched Updates

MobX automatically batches updates to avoid triggering reactions multiple times:

javascript
runInAction(() => { store.firstName = 'Jane'; store.lastName = 'Smith'; store.age = 25; });

Even if multiple observables are modified, related reactions will only execute once.

Dependency Cleanup

When a reaction is no longer needed, MobX automatically cleans up dependency relationships:

  • When components unmount, observers automatically clean up
  • Use dispose() method to manually clean up reactions
  • Avoid memory leaks

Performance Optimization

MobX's dependency tracking system provides multiple performance optimizations:

  1. Lazy calculation: Computed values are only calculated when needed
  2. Caching mechanism: Results of computed values are cached
  3. Batched updates: Multiple state changes are merged into one update
  4. Fine-grained tracking: Only tracks truly needed dependencies

Debugging Dependency Tracking

MobX provides debugging tools to view dependency relationships:

javascript
import { trace } from 'mobx'; // Track dependencies of computed trace(store.fullName); // Track dependencies of reaction autorun(() => { console.log(store.count); }, { name: 'myReaction' });

Common Issues

1. Circular Dependencies

MobX can detect and avoid circular dependencies, but they should be avoided in design.

2. Over-tracking

Avoid accessing observables in loops or conditions, as this may lead to unnecessary dependencies.

3. Memory Leaks

Ensure reactions are cleaned up when components unmount to avoid memory leaks.

Summary

MobX's dependency tracking system achieves efficient reactive updates through the observer pattern and dependency graph. Understanding how this system works helps write more efficient MobX code and avoid common performance issues.

标签:Mobx