Skip to content

watch ​

watch subscribes to value changes of an atom in the active store, which is determined by the current execution context.

ts
const watcher = watch($atom, ...familyArgs, listener)
ts
function watch<T extends AnyAtom>(
  atom: T,
  ...args: [...AtomFamilyArgsOf<T>, AtomListener<T>]
): AtomWatcher<T>

type AtomWatcher<T extends AnyAtom = AnyAtom> = {
  readonly clear: () => void
}

Reference ​

watch(atom, ...familyArgs, listener) ​

Call watch anywhere in your code. The method is context-aware and its behavior varies.

Normal usage ​

ts
import {watch} from 'reago';

function $atom() {
  // ...
}

const watcher = watch($atom, () => {
  // $atom value changed in the built-in default store
});

// when not needed anymore
watcher.clear();

A watch call outside of a computation context defaults to reading from the built-in default store. It is a shorthand for getDefaultStore().watch().

Usage within an atom ​

Using watch within an atom is forbidden. Use read to subscribe to another atom.

Usage within a hook callback ​

ts
import {atomMountEffect, watch} from 'reago';

function $atom() {
  return 42;
}

function $atomWithCallbacks() {
  atomMountEffect(() => {
    const watcher = watch($atom, () => {
      // $atom value changed in the active store
    });
    return () => watcher.clear();
  });
}

A watch within a hook callback in an atom is also context-aware, and similarly, uses the store the atom computation was running in.

Parameters ​

  • atom: A reference to an atom you want to watch.
  • ...familyArgs: If the atom is a family (meaning it accepts arguments, where each unique combination of arguments represents a separate atom with its own state), these are the atom arguments.
  • listener: A callback invoked every time the value of the atom changes.

Behavior ​

watch creates a watcher that will notify you of changes to the value of the given atom.

Creating a watcher mounts the atom if it is not already mounted. It also triggers any pending computations of the atom, if it is not computed or outdated.

You will not be notified for the value the atom had at the moment watch was called. The provided listener will fire only for subsequent changes.

Returns ​

watch returns a watcher object representing the created observer.

The returned object has only one method:

  • .clear(): Discards the watcher and stops observing the given atom. The atom might be unmounted if it is no longer subscribed to by anyone.

CAUTION

It is highly important to discard watchers that are no longer needed, otherwise you risk leaking atoms that will be never unmounted and will be unnecessarily recomputed. If you're using framework-specific bindings, such as React's useRead*Atom, they manage the lifecycle of watchers on their own.

Caveats ​

  • Reago can track execution context across synchronous calls and generative atoms only. If you define an asynchronous callback within a hook callback and try calling watch inside, we will not be able to determine the active store.

Examples ​

Watching the default store ​

Call watch anywhere outside of the computation context to watch the default store.

ts
import {atomMountEffect, atomReducer, read, watch} from 'reago';

function $increasingAtom() {
  const [counter, tick] = atomReducer(x => x + 1, 0);
  atomMountEffect(() => {
    const interval = setInterval(tick, 1000);
    return () => clearInterval(interval);
  }, []);
  return counter;
}

console.log(`Counter starts at ${read($increasingAtom)}`);

const watcher = watch($increasingAtom, () => {
  console.log(`Counter is now at ${read($increasingAtom)}`);
});

// when not needed anymore
watcher.clear();

Released under the MIT License.