02 @dirtytalk/structural

Structural

Paths light up. Only their readers wake.

Chapter 02 Watch structural run, interactively →

@dirtytalk/structural tracks changes in objects and arrays. A region is a set of interned path IDs, and each consumer subscribes to the paths it actually read.

pnpm add @dirtytalk/structural @dirtytalk/engine

Container

Extend StructuralContainer and mutate through the protected patch, emit or update.

import { StructuralContainer, ALL_PATHS } from '@dirtytalk/structural';
import { MicrotaskScheduler } from '@dirtytalk/engine';

interface CounterState {
  count: number;
  label: string;
}

class Counter extends StructuralContainer<CounterState> {
  constructor() {
    super(
      { count: 0, label: 'counter' },
      { scheduler: new MicrotaskScheduler() },
    );
  }

  increment() {
    this.patch({ count: this.state.count + 1 });
  }
}

const counter = new Counter();

const unsub = counter.channel.subscribe(
  () => ALL_PATHS,
  (dirty) => console.log(counter.state, dirty),
);

counter.increment();

React

import { useStructural } from '@dirtytalk/structural/react';

const counter = new Counter();

function Count() {
  const [state, container] = useStructural(counter);
  return <button onClick={() => container.increment()}>{state.count}</button>;
}

Only fields read during render are recorded, so a change to label won’t re-render Count.

Other exports

ExportPurpose
PathInternerstring to ID interning, shared per class
PathSet, PathSetSpacethe region type and its Space
trackRender, ProxyCachethe proxy recorder behind useStructural
diffAlongSkeleton, pathsFromPatch, getAtdiff and path helpers

Values read from a tracked proxy are proxies too. Use raw() before comparing by identity or storing them.