Skip to content

useWatch

useWatch runs a handler when a value the server owns moves — a game variable, a skill, an inventory — or when the client announces one of its occasions. Nothing is redrawn.

useWatch(source: WatchSource | WatchSource[], handler: Handler, on?: Ref): void
src/watch.ts2
export const PoisonWatch = (): Component => {
useWatch(Varps.POISON, (event) => { writePoison(event.component); }, poisonLabel);
src/watch.ts2
const writePoison = (into: ComponentId): void => {
const poison = useServerState(Varps.POISON);
into.text = poison > 0 ? `Poison: ${poison}` : 'Poison: none';
};
  • source: What to watch — a Varps.* or Varbits.* reference, a Skills.* reference, an Inventories.* reference, or an Engine.* occasion. Or a list of several of one kind: useWatch([A, B], handler).
  • handler: An ordinary handler. It is told nothing about what changed; event.component is the component the watch is bound on.
  • on: A ref naming the component the watch lives on — its host. Defaults to this component’s root.

Nothing.

  • It redraws nothing.
  • One kind per call (TS2E218). A varbit watch fires when its containing variable moves.
  • A cell the handler writes and the render never reads is refused (TS2E228). Read the cell, or use useRerenderOn when a redraw is what you wanted.
  • A hidden host does not fire. A watch under a hide fires once shown.
  • A host scrolled out of sight does not fire until it scrolls back; put the watch on a host outside the scrolling layer.
  • A .map() row cannot call a hook (TS2E203). For a watch on each row, make the row a component.
  • A host in a box 0 wide or 0 tall is refused (TS2E252); give the box w={1} h={1}. Engine.SUB_CHANGE and Engine.DIALOG_ABORT are the exceptions.
  • event.component inside the handler is the host, so a handler that rewrites itself has to be bound on itself — the third argument, usually a module-scope createRef.
  • The handler’s reads are point-in-time, like any handler’s. useServerState inside it is a read of the moment and no subscription.
refused/use-watch.ts2
useWatch([Varps.POISON, Skills.ATTACK], () => { label.color = Colors.GREEN; }); // two kinds
refused/use-watch-cell.ts2
const [, setSeen] = useState(0); // never read
useWatch(Varps.POISON, () => { setSeen(1); });
src/watch.ts2
const poisonLabel = createRef('docs-watch:poison');
src/watch.ts2
<text ref={poisonLabel} x="right" y="center" w={120} h={16} text="Poison: -"
font={Fonts.PLAIN} align="right" valign="middle" shadow color={Colors.WHITE}
onLoad={(event) => { writePoison(event.self); }} />

onLoad fills the label as the interface opens; the watch updates it after.

src/watch.ts2
export const PoisonChanges = (): Component => {
const [changes, setChanges] = useState(0);
useWatch(Varps.POISON, () => { setChanges(changes + 1); });
src/deaf.ts2
useWatch(Varps.POISON, () => {
const poison = useServerState(Varps.POISON);
label.text = poison > 0 ? `Poison ${poison}` : 'No poison';
}, host);
src/reference-engine.ts2
useWatch(Engine.SUB_CHANGE, (event) => { writeDivider(event.component); }, label);

Engine names the ten.

Look up the tree for a hide, and check the host’s box is not 0 on either axis. Then check the source is the one that moves: a watch on a varbit fires when the variable containing it moves.

Read the cell in the render, or reach for useRerenderOn if the point was to redraw.