Event handlers are batches
Every handler the framework dispatches runs inside batch: delegated events (onClick, onInput, onKeyDown, ...) and natively bound ones (onFocus, onBlur, ...).
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>
);
}