有限 / 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 NOT_FETCHED = 'not fetched'
const FETCHING = 'fetching'
const FETCHED = 'fetched'
const FETCH_FAILED = 'fetch failed'
export const fetchTransition = 'fetch'
type TodoState = typeof NOT_FETCHED | typeof FETCHING | typeof FETCHED | typeof FETCH_FAILED
export const todoMachine = createMachine<TodoState, string[]>({
state: NOT_FETCHED,
value: [],
transitions: {
[fetchTransition]: {
sourceState: NOT_FETCHED,
targetState: FETCHING,
effect: (value) => {
return new Promise((resolve, reject) => {
setTimeout(() => resolve([...value, 'shopping']), 2000)
})
},
successState: FETCHED,
failureState: FETCH_FAILED,
},
},
})
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)
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 observerd 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.