Watching Changes
Managing State
Section titled “Managing State”Reset the watcher to clear all tracked changes:
const watcher = Watcher.get(model);
runInAction(() => { model.name = "John";});
watcher.changed // truewatcher.changedKeys // Set(["name"])
// Clear all tracked changeswatcher.reset();
watcher.changed // falsewatcher.changedKeys // Set()watcher.changedTick // 0nMark the watcher as changed without incrementing the tick (useful for external state synchronization):
watcher.assumeChanged();
watcher.changed // truewatcher.changedTick // 0n (not incremented)Observing Changes
Section titled “Observing Changes”The changedTick property is a counter that increments with each tracked change.
class Model { @observable name = ""; @observable age = 0;
constructor() { makeObservable(this); }}
const model = new Model();const watcher = Watcher.get(model);
watcher.changedTick // 0n
runInAction(() => { model.name = "John"; model.age = 30;});
// Each change increments the tickwatcher.changedTick // 2n (one for name, one for age)watcher.changedKeys // Set(["name", "age"])
watcher.reset();
// After reset, both changedKeys and changedTick are clearedwatcher.changedKeys // Set()watcher.changedTick // 0nMost useful with reaction() to trigger side effects when changes occur:
const model = new Model();const watcher = Watcher.get(model);
// React to any tracked changesreaction( () => watcher.changedTick, () => { // Process changes here... saveToBackend(model); });
runInAction(() => { model.name = "John"; model.age = 30;});// Reaction triggers once after the transaction completesTemporarily Disable Tracking
Section titled “Temporarily Disable Tracking”Use unwatch() as a function to run code without changes being detected by Watcher.
const model = new Model();const watcher = Watcher.get(model);
// Changes inside unwatch() are not trackedunwatch(() => { model.name = "John"; model.age = 30;});
watcher.changed // false
// Normal changes are still trackedrunInAction(() => { model.name = "Jane";});
watcher.changed // trueOnly what the function itself changes goes untracked. Watching resumes as soon as it returns, so the changes made around it are tracked as usual, even when all of it happens in one transaction.
runInAction(() => { model.field1 = true; // Tracked: before unwatch begins
unwatch(() => { model.field2 = true; // Not tracked });
model.field3 = true; // Tracked: unwatch has returned});
watcher.changedKeys // Set(["field1", "field3"])⚠️ One limitation: a watcher processes the changes of a transaction when the outermost one ends, where all it can tell is when a key first changed in it. So a key the function changes stays untracked for the rest of that transaction:
runInAction(() => { unwatch(() => { model.field1 = true; // Not tracked });
model.field1 = false; // ⚠️ NOT tracked: the same key, already changed inside unwatch model.field2 = true; // Tracked: a different key});
watcher.changedKeys // Set(["field2"])The reverse order is fine: a key changed before the function and again inside it is tracked.