Open-Source Wikis

/

tldraw

/

Packages

/

@tldraw/state

tldraw/tldraw

@tldraw/state

Active contributors: David Sheldrick, Steve Ruiz

Purpose

@tldraw/state is a reactive signals library. Inspired by S.js / SolidJS / MobX, it provides Atom (writable signal), Computed (derived signal that auto-tracks dependencies), reactions, and transactions. It is the foundation that @tldraw/store and @tldraw/editor are built on, and it ships as its own npm package for downstream use.

Directory layout

packages/state/
├── package.json
└── src/
    ├── index.ts
    └── lib/
        ├── Atom.ts                  # writable atoms
        ├── Computed.ts              # derived computeds
        ├── EffectScheduler.ts       # reactor scheduling
        ├── HistoryBuffer.ts         # change history within a single signal
        ├── ArraySet.ts              # internal sparse set
        ├── transactions.ts          # transact, deferAfterTransaction
        ├── capture.ts               # tracking captureStack management
        ├── localStorageAtom.ts      # atom backed by localStorage
        ├── helpers.ts
        ├── isComputed.ts
        ├── isSignal.ts
        ├── types.ts
        ├── constants.ts
        └── warnings.ts

Key abstractions

Type File Purpose
Atom<T> packages/state/src/lib/Atom.ts Writable reactive value. atom('name', initial).
Computed<T> packages/state/src/lib/Computed.ts Derived value with auto-tracked dependencies. computed('name', () => ...).
Reactor packages/state/src/lib/EffectScheduler.ts Side-effecting reaction. reactor('name', () => ...).
react() packages/state/src/lib/EffectScheduler.ts Helper that creates a reactor and starts it.
transact() packages/state/src/lib/transactions.ts Batches mutations so subscribers see one update.
unsafe__withoutCapture() packages/state/src/lib/capture.ts Read inside a computed without tracking.
Signal<T> packages/state/src/lib/types.ts Common interface (get, lastChangedEpoch, …) implemented by both atoms and computeds.
localStorageAtom() packages/state/src/lib/localStorageAtom.ts Atom whose value is mirrored to localStorage.

How it works

graph LR
    Atom -->|read inside| Computed
    Computed -->|read inside| Reactor
    Atom -->|set| Transaction
    Transaction -->|on commit| Computed
    Transaction -->|on commit| Reactor

Reads inside computed() build a dependency graph. When an atom changes, the change is propagated through the graph; downstream computeds invalidate lazily and reactors run synchronously at the end of the current transaction. Writes outside a transact are an implicit transaction of size one.

The library is small, fast, and stable — it is one of the longest-untouched corners of the repo.

React integration

Lives in a separate package: @tldraw/state-react. The most-used hooks are useValue (subscribe to a signal in a component), useComputed, useStateTracking, and track (HOC for fine-grained re-renders).

Usage examples

import { atom, computed, react, transact } from '@tldraw/state';

const count = atom('count', 0);
const doubled = computed('doubled', () => count.get() * 2);

react('log', () => {
  console.log('count is', count.get(), 'doubled is', doubled.get());
});

transact(() => {
  count.set(1);
  count.set(2); // only one log
});

Integration points

  • Imports. None at runtime (no dependencies).
  • Importers. @tldraw/store, @tldraw/state-react, @tldraw/editor (transitively re-exports).

Entry points for modification

  • Performance work lives in Computed.ts (epoch tracking) and EffectScheduler.ts (queueing). Both are well-tested.
  • New helpers belong in helpers.ts if generic, or in their own file if they have a meaningful surface.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

@tldraw/state – tldraw wiki | Factory