batch()
Group multiple signal writes so that effects run only once at the end.
batch(fn)
Parameters
| Parameter | Type | Description |
|---|---|---|
fn |
() => void |
A function containing multiple signal writes. All dependent effects are deferred until the function completes. |
Returns
void. The function does not return a value.
Usage
Basic Batching
The difference batch() makes is timing, not the number of runs.
Two writes in the same synchronous block already collapse into a single queued run. What
batch() changes is that the run happens synchronously at the closing brace, so
the code after the batch sees the effect already applied.
import { signal, effect, batch } from 'what-framework';
const firstName = signal('John');
const lastName = signal('Doe');
const seen = [];
effect(() => {
seen.push(`${firstName()} ${lastName()}`);
});
// Without batch: one run, but not until the next microtask
firstName.set('Jane');
lastName.set('Smith');
console.log(seen); // ["John Doe"] - not applied yet
await Promise.resolve();
console.log(seen); // ["John Doe", "Jane Smith"]
// With batch: the same single run, flushed before the next line
batch(() => {
firstName.set('Bob');
lastName.set('Jones');
});
console.log(seen); // ["John Doe", "Jane Smith", "Bob Jones"]
Form State Updates
const formData = signal({ name: '', email: '' });
const errors = signal({});
const submitting = signal(false);
function resetForm() {
batch(() => {
formData.set({ name: '', email: '' });
errors.set({});
submitting.set(false);
});
}
Nested Batching
// Batch calls can be nested. Effects flush
// only when the outermost batch completes
batch(() => {
firstName.set('Alice');
batch(() => {
lastName.set('Wonder');
});
// inner batch doesn't flush yet
});
// NOW the effect runs once
How It Works
Internally, batch() increments a depth counter. While the counter is above zero, all signal notifications queue pending effects instead of scheduling them. When the outermost batch() completes, the counter returns to zero and all queued effects are flushed synchronously.
Notes
- Effects already batch naturally via microtask scheduling. If multiple signal writes happen in the same synchronous block, effects run once in the next microtask. Use
batch()when you need to guarantee effects see a consistent state across multiple writes. - Batch calls can be nested. Effects only flush when the outermost batch completes.
- The flush inside batch is synchronous, unlike the default microtask scheduling. This can be useful when you need effects to run before continuing.
- If the function passed to
batch()throws, the batch depth is still decremented correctly and pending effects are still flushed, and the error is then re-thrown to the caller.batch()usestry/finally, it is not atry/catch.