Skip to content

Batching

Group multiple signal updates to run observers only once.

Batching lets you group several signal writes so dependent computeds and effects flush once after the batch finishes.

Info: Updates still happen synchronously. Batching changes how many times dependents flush, not whether they flush immediately.

Why and When to Batch

Why Batch?

Without batching, each write can trigger a new round of downstream work. That is fine for isolated updates, but noisy for coordinated state changes.

1let firstName = Signal.make("Ada")
2let lastName = Signal.make("Lovelace")
3
4let fullName = Computed.make(() =>
5 Signal.get(firstName) ++ " " ++ Signal.get(lastName)
6)
7
8Effect.run(() => {
9 Console.log(Signal.get(fullName))
10 None
11})
12
13Signal.set(firstName, "Grace")
14Signal.set(lastName, "Hopper")

That effect can run twice. If both writes belong to the same logical update, batch them.

Using Batching

Using Signal.batch()

Wrap related writes in Signal.batch.

1Signal.batch(() => {
2 Signal.set(firstName, "Grace")
3 Signal.set(lastName, "Hopper")
4})

How Batching Works

Inside a batch, signals update immediately, but scheduler flushing is deferred until the outermost batch completes. Readers inside the batch still see the latest values.

1Signal.batch(() => {
2 Signal.set(firstName, "Grace")
3 Signal.set(lastName, "Hopper")
4
5 Console.log(Signal.peek(firstName)) // "Grace"
6 Console.log(Signal.peek(lastName)) // "Hopper"
7})

Common Cases

Batching is most useful when one user action updates several related signals.

1type formState = {
2 name: string,
3 email: string,
4}
5
6let form = Signal.make({name: "", email: ""})
7let isSaving = Signal.make(false)
8let saveError = Signal.make(None)
9
10let submit = () => {
11 Signal.batch(() => {
12 Signal.set(isSaving, true)
13 Signal.set(saveError, None)
14 })
15}

Nested Batches

Batches can be nested. Flushing happens when the outermost batch ends.

1Signal.batch(() => {
2 Signal.set(count, 1)
3
4 Signal.batch(() => {
5 Signal.set(count, 2)
6 Signal.set(count, 3)
7 })
8})

Returning Values from Batches

A batch returns whatever the callback returns, so you can compute and write in one block.

1let result = Signal.batch(() => {
2 Signal.set(count, 10)
3 Signal.set(status, "ready")
4 "ok"
5})

When Not to Batch

Do not batch by default. If one signal changes and the rest of the graph can react naturally, batching adds no clarity. Use it when several writes are one semantic update.

Working Style

Best Practices

  • Batch one logical unit of work, such as a submit action, a reset, or a reducer-style update.
  • Keep batches short so the write order stays easy to reason about.
  • Do not use batching to hide duplicated or awkward state. Fix the model first.

Next Steps