Skip to content

watch / unwatch

The watch function lets you observe property changes programmatically.

Signature

typescript
function watch<T>(ref: HookRef<T>, callback: (newValue: T, state: Record<string, any>) => void): () => void
function unwatch<T>(ref: HookRef<T>, callback: (newValue: T, state: Record<string, any>) => void): void
  • ref — A reactive reference (e.g., state.$count).
  • callback — Function called with the new value and a plain state snapshot whenever it changes.
  • Returns — An unsubscribe function.

Basic Usage

typescript
import { createHook, watch } from "croft";

const state = createHook({ count: 0 });

const unsubscribe = watch(state.$count, (newCount) => {
  console.log("Count is now:", newCount);
});

state.count = 5; // Logs: "Count is now: 5"

// Stop watching
unsubscribe();

Accessing Other State

The callback receives a plain object snapshot of all hook properties as the second argument. This is useful when one property's change depends on another:

typescript
const state = createHook({ todos: [], filter: "all" });

watch(state.$todos, (newTodos, snapshot) => {
  // snapshot is a plain object — NOT a Proxy
  // snapshot.filter has the current filter value
  localStorage.setItem("todos", JSON.stringify(newTodos));
});

watch(state.$filter, (newFilter, snapshot) => {
  // snapshot.todos is the current todos at the time of the change
  const filtered = newFilter === "all"
    ? snapshot.todos
    : snapshot.todos.filter(t => /* ... */);
  updateUI(filtered);
});

The second parameter is a shallow { ...target } copy — it's a plain object, not a Proxy. Writing to it won't trigger watchers.

localStorage Persistence

typescript
const STORAGE_KEY = "my-app-state";

const loadState = () => {
  try {
    return JSON.parse(localStorage.getItem(STORAGE_KEY) || "{}");
  } catch {
    return {};
  }
};

const state = createHook(loadState());

watch(state.$state, (newState) => {
  localStorage.setItem(STORAGE_KEY, JSON.stringify(newState));
});

Multiple Watchers

You can add multiple watchers to the same reference:

typescript
watch(state.$count, (n) => console.log("watcher 1:", n));
watch(state.$count, (n) => console.log("watcher 2:", n));

unwatch

typescript
const fn = (n) => console.log(n);
watch(state.$count, fn);

// Later:
unwatch(state.$count, fn);

Notes

  • The callback fires after the value has been set.
  • During the callback, the new value is already available on the state object.
  • The second argument is a plain snapshot — modifying it won't trigger reactivity.
  • Watch callbacks are synchronous.