[]previous and next page

The mental model: components run once

A React component is a function that runs again on every state change, and hooks rebuild their values from the previous render.

For agentsUpdated

A React component is a function that runs again on every state change, and hooks rebuild their values from the previous render. A ShadowJS component is a setup function. It runs once, builds real DOM nodes, and the compiler wires every {expression} that reads a signal to the one text node or attribute it fills. Nothing re-renders, so there are no dependency arrays, no stale closures and no rules of hooks.

React ShadowJS
The component function runs on every update The component function runs once per instance
A virtual DOM is diffed Signals update the exact node that reads them
State is read as a plain variable State is read by calling an accessor: count()
useEffect(fn, [a, b]) useEffect(fn) tracks whatever fn reads
useMemo, useCallback, memo to avoid re-renders Not needed. Nothing re-renders
Hooks must run in the same order Hooks are ordinary calls and may be conditional

The first block counts how often the component body runs. It prints setup once, during the mount that the page test performs.

src/counter.tsxtsx
import { useStore } from "@shadow-js/core";

export function Counter() {
  console.log("setup");
  const [count, setCount] = useStore(0);
  return (
    <button type="button" onClick={() => setCount((n) => n + 1)}>
      {count()}
    </button>
  );
}
Expected output
setup

Two clicks later the body has still run once, and the same text node holds the new value.