Skip to content

Yugen: A framework-agnostic, lightweight, robust and intuitive state manager

有限 / Yūgen: japanese for finite, as in deterministic finite automaton

Yugen models state management as a deterministic finite automaton. Below is the state machine for a TodoStore, which fetches todos.

The code looks like this:

TypeScript
// stores/todoStore.ts
import { createMachine } from '@yugen/machine'

const notFetched = 'not fetched'
const fetching = 'fetching'
const fetched = 'fetched'
const fetchFailed = 'fetch failed'

export const fetchTransition = 'fetch'

type TodoState = typeof notFetched | typeof fetching | typeof fetched | typeof fetchFailed

export const todoMachine = createMachine<TodoState, string[]>({
  state: notFetched,
  value: [],
  transitions: {
    [fetchTransition]: {
      sourceState: notFetched,
      targetState: fetching,
      effect: (currentValue, newValue) => {
        return new Promise((resolve, reject) => {
          setTimeout(() => resolve([...currentValue, newValue]), 2000)
        })
      },
      successState: fetched,
      failureState: fetchFailed,
    },
  },
})

You can then use the todoMachine like this:

TypeScript
// pages/todoList.ts
import { todoMachine, fetchTransition } from '../stores/todoStore.ts'

console.log(todoMachine.state) // not fetched
console.log(todoMachine.value) // []

todoMachine.transitionTo(fetchTransition, 'shopping')

console.log(todoMachine.state) // fetching
console.log(todoMachine.value) // []

// after 2000ms

console.log(todoMachine.state) // fetched
console.log(todoMachine.value) // ['shopping']

Why

Over the past years we observed that state management in frontend can be quite complex and prone for error. This is why Yugen was born as part of a bachelors' thesis.

What it is

Framework-agnostic: @yugen/machine does not rely on any UI framework.

Lightweight: @yugen/machine contains very little code that is easy to understand. We also prioritize ESM.

Robust: Yugen is well tested and strictly follows the same transition concept as in DFAs.

Intuitive: After experimenting with a lot of state managers, we tried to include the best aspects of each into Yugen. We try to minimize boilerplate.

What it's not

Reactive: Yugen is not reactive. It means that changes in state will not update the UI automatically. @yugen/signal is also not reactive, because it relies on Stage 1 ECMAScript Signal implementation and not the ones used in the UI frameworks. We plan to add adapters for framework signals, such as ref and reactive in Vue, signal in Angular and @preact/signals-react for React.

Traceable: Yugen, unlike Redux and NgRx does not have devtools yet. So you cannot trace changes in state easily.

Further