Observable.get default access dependency tracking
0 reputation · 14 Apr 2023, 08:06 UTC
0 reputation · 14 Apr 2023, 08:06 UTC
When using observable.get(key, fallback) to safely read a property that may be undefined, MobX returns the fallback value without registering the property as a dependency.
The goal is to have any observer or reaction that relies on this property re‑run when the property later becomes defined, avoiding stale UI state.
Currently the access does not create a dependency, so reactions stay dormant until another observable change forces a re‑evaluation, which can lead to subtle cache‑miss bugs.
It is unclear whether this behavior should be changed, made configurable via a flag, or left as‑is with documentation recommending alternative patterns.
Should MobX provide a configuration option to treat default‑value accesses as dependencies? If not, what patterns guarantee dependency tracking without manual triggers? Would treating the default access as a dependency break existing code that relies on the current behavior?
In MobX (specifically 6.x), dependency tracking is triggered by the actual access of an existing observable property. When using a pattern like observable.get(key, fallback), if the key does not exist, the property getter is never invoked on the observable object. Consequently, the reaction (observer or reaction) does not register a dependency on that specific key, and the UI will not update when that key is eventually defined.
Confirmed Fact: MobX tracks accesses, not intent. If the execution path returns a fallback without touching an observable property, no dependency is created. This is consistent with how MobX optimizes performance by avoiding the tracking of every possible key in a dynamic object.
Likely Explanation: Treating a missing key as a dependency would require MobX to track the entire keyset (the "shape") of the object for every get call. This would significantly increase memory overhead and potentially cause excessive re-renders whenever any property is added or removed from the object, regardless of whether that specific property is used.
To ensure a reaction triggers when a property moves from undefined to a defined value, use one of the following strategies:
observable.map(). Maps in MobX track additions and removals of keys. Accessing a missing key in a map still registers a dependency on the map's internal state.undefined. Since the key exists, the getter is invoked, and the dependency is registered.You can verify this behavior with the following scoped test:
import { observable, autorun } from "mobx";
const state = observable({ a: 1 });
// This will NOT trigger when 'b' is added
autorun(() => {
console.log("Value:", state.b ?? "fallback");
});
state.b = 2; // No log output
To resolve this, swapping state to observable.map({ a: 1 }) will cause the autorun to trigger immediately upon state.set('b', 2).
Are you utilizing observable.map or plain observable objects for these dynamic keys? The recommendation differs significantly based on the data structure used.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.