有限 / 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:
// 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:
// 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']
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. Beside the source code, you will also find the
thesis here. It includes the design decisions and a comparison to other state management libraries.
Framework-agnostic: @yugen/machine
does not rely on any UI framework. It is the core of @yugen/signal
which on the other hand uses the Stage 1 ECMAScript Signal implementation.
Lightweight: @yugen/machine
contains very little code that is easy to understand. We also prioritize ESM.
Robust: Yugen
is well tested and abstracts away 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.
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.