Chapter 02 @dirtytalk/structural

Paths light up.

State is a tree, and every component reads a few paths of it. Structural records those reads, so a change wakes only the readers. This stage runs the real @dirtytalk/structural.

01

State is a tree of paths.

A StructuralContainer holds plain state. Every key is a path: user.name, cart.total, theme. The tree on the left is the live state, and nothing in it is hot yet.

02

Reads are recorded.

A component renders against a tracking proxy, and each property it touches is recorded. Header read user.name. CartBadge read only the length of the items. The cyan paths are what each one subscribed to.

const { value, paths } = trackRender(state, interner);
// paths: Set { user.name }
channel.subscribe(() => paths, rerender);

03

A patch marks paths.

patch({ user: { name } }) marks the keys you gave it, plus their parents. update(fn) and emit(next) diff the old state against the new one, but only along paths somebody read.

container.patch({ user: { name: 'Grace' } });
container.update((s) => ({ ...s, theme: 'light' }));

04

Only readers wake.

The channel intersects the changed paths with each reader's paths. Adding an item changes cart.items.length and cart.total, which wakes CartBadge and Total. Header and ThemeToggle never hear about it.

05

Absent keys are tracked too.

NickTag read user.nickname, which doesn't exist yet. The miss is recorded like any other read, so setting the key later wakes it. Changing user.avatar, which nobody read, marks the path but wakes nobody.

container.patch({ user: { nickname: 'Ada' } });

06

Your turn.

Fire any mutation and watch the counters: paths changed, then consumers woken out of five. Try changing the avatar, then the nickname.

state
user
cart
theme
name
avatar
nickname
items
total
length
Header 0 wakes
NickTag 0 wakes
CartBadge 0 wakes
Total 0 wakes
ThemeToggle 0 wakes

0 paths changed → 0 / 5 woken