Skip to content

Computed

Computeds are values derived from context (or other computeds). They are lazy (only evaluated when read) and memoized (only re-evaluated when an input they actually read changes).

import { machine } from '@dunky.dev/state-machine'
const m = machine({
initial: 'idle',
context: { items: ['a', 'b', 'c'] },
computed: {
count: ({ context }) => context.items.length,
isEmpty: ({ computed }) => computed.count === 0, // derives from another computed
},
states: { idle: {} },
})
m.start()
m.computed.count // 3
m.computed.isEmpty // false

A computed value is accessible anywhere context is (guards, actions, effects, watchers) via { computed } in the $ argument:

states: {
idle: {
on: {
submit: {
guard: ({ computed }) => !computed.isEmpty,
actions: ({ computed }) => console.log('items:', computed.count),
},
},
},
}

The classic use case: filter or derive a list from context fields rather than keeping a parallel list in state.

const m = machine({
initial: 'idle',
context: { query: '', items: ALL_ITEMS, activeIndex: -1 },
computed: {
filtered: $ => $.context.items.filter(i => i.label.includes($.context.query)),
highlighted: $ => $.computed.filtered[$.context.activeIndex] ?? null,
},
states: { idle: {} },
})

filtered only recomputes when query or items changes. highlighted only recomputes when filtered or activeIndex changes. The memoization is automatic: no useMemo, no manual deps.