[]previous and next page

Event handlers are batches

Every handler the framework dispatches runs inside batch: delegated events (onClick, onInput, onKeyDown, ...) and natively bound ones (onFocus, onBlur, ...).

For agentsUpdated

Every handler the framework dispatches runs inside batch: delegated events (onClick, onInput, onKeyDown, ...) and natively bound ones (onFocus, onBlur, ...). When the handler returns, the DOM and the user effects are current. This is why event code needs no flushSync.

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

export function Counter(props: { onEffect?: (count: number) => void }) {
  const [count, setCount] = useStore(0);
  useEffect(() => {
    props.onEffect?.(count());
  });
  return (
    <button
      type="button"
      onClick={() => {
        setCount(count() + 1);
        setCount(count() + 1);
      }}
      onFocus={() => setCount(count() + 10)}
    >
      {count()}
    </button>
  );
}