StunkStunk
Core Concepts

Batch Updates

Group multiple chunk updates into a single notification cycle.

By default, every set() call immediately notifies all subscribers. Updating multiple chunks at once triggers a separate notification per chunk — meaning a separate re-render per chunk in React.

batch() solves this by collecting all updates inside a callback and firing a single notification after all of them complete.

import { chunk, batch } from "stunk";

const firstName = chunk("Fola");
const lastName = chunk("Ade");
const age = chunk(25);

// Without batch — 3 separate notifications
firstName.set("Tunde");
lastName.set("Bello");
age.set(30);

// With batch — 1 notification after all three updates
batch(() => {
  firstName.set("Tunde");
  lastName.set("Bello");
  age.set(30);
});

How it works

  1. A batching flag is set internally
  2. Every set() inside the callback marks the chunk as dirty instead of notifying immediately
  3. After the callback completes, all dirty chunks notify their subscribers once with the final value
  4. The batching flag is cleared

Subscribers always receive the final value after all mutations — intermediate values are never seen.


In React

batch() is especially useful when updating multiple related chunks that feed into the same component:

import { chunk, batch } from "stunk";
import { useChunk } from "stunk/react";

const firstName = chunk("Fola");
const lastName = chunk("Ade");

function NameForm() {
  const [first, setFirst] = useChunk(firstName);
  const [last, setLast] = useChunk(lastName);

  const handleReset = () => {
    batch(() => {
      setFirst("Fola");
      setLast("Ade");
    });
    // component re-renders once, not twice
  };

  return (
    <div>
      <p>
        {first} {last}
      </p>
      <button onClick={handleReset}>Reset</button>
    </div>
  );
}

React 18 automatically batches state updates inside event handlers. batch() is still useful for updates outside React events — timeouts, async callbacks, or vanilla JS code.


Nested batches

batch() calls can be nested safely. The outermost batch controls when notifications fire — inner batches don't flush early.

batch(() => {
  firstName.set("Tunde");

  batch(() => {
    lastName.set("Bello");
    age.set(30);
  });

  // still batched — no notifications yet
});
// all three notify here, once

With computed chunks

batch() works correctly with computed() — the computed value recomputes after all source chunks have been updated:

const price = chunk(100);
const quantity = chunk(3);
const total = computed(() => price.get() * quantity.get());

batch(() => {
  price.set(50);
  quantity.set(10);
});

total.get(); // 500 — computed once after both updates, not twice

Error safety

If an error is thrown inside a batch() callback, the batch still flushes any updates that completed before the error:

batch(() => {
  count.set(1); // this runs
  throw new Error("oops");
  count.set(2); // unreachable
});
// count is 1, subscribers notified

What's next?

On this page