Skip to content

Batch & Untrack

batch(fn)

Batch multiple signal updates into a single reactive cycle. Without batching, each set call immediately notifies dependents. Inside a batch, all notifications are deferred until the batch completes.

tsx
import { sig, val, set, batch } from "@hedystia/view";

const firstName = sig("Alice");
const lastName = sig("Smith");

// Without batch: effects run twice (once per set)
// With batch: effects run once after both updates
batch(() => {
  set(firstName, "Bob");
  set(lastName, "Jones");
});

When to Use

  • Updating multiple related signals at once
  • Avoiding intermediate renders during complex state transitions
  • Performance-critical update paths

untrack<T>(fn)

Execute a function without tracking any signal reads as dependencies. Reads inside untrack won't cause the surrounding effect or memo to re-run when those signals change.

tsx
import { sig, val, untrack } from "@hedystia/view";
import { on } from "@hedystia/view";

const count = sig(0);
const label = sig("Count");

// Only re-runs when `count` changes, NOT when `label` changes
on(
  () => val(count),
  (c) => {
    const currentLabel = untrack(() => val(label));
    console.log(`${currentLabel}: ${c}`);
  },
);

JSX Example

tsx
import { sig, val, set, batch, mount } from "@hedystia/view";

function ProfileForm() {
  const name = sig("Alice");
  const email = sig("alice@example.com");
  const status = sig("saved");

  const handleReset = () => {
    batch(() => {
      set(name, "");
      set(email, "");
      set(status, "cleared");
    });
  };

  return (
    <div>
      <input
        value={() => val(name)}
        onInput={(e) => set(name, (e.target as HTMLInputElement).value)}
      />
      <input
        value={() => val(email)}
        onInput={(e) => set(email, (e.target as HTMLInputElement).value)}
      />
      <p>Status: {() => val(status)}</p>
      <button onClick={handleReset}>Reset</button>
    </div>
  );
}

mount(ProfileForm, document.getElementById("root")!);