Framework-agnostic state management library designed for simplicity and scalability

Simple primitives

xoid is based on atoms. Atoms are standalone setter/getter objects that hold state. create function is used to create them.

It has a Recoil-inspired API for derived atoms.

import { create } from 'xoid'
const atom = create(3)
atom() // 3 (get the value)
atom(5) // void (set the value to 5)
atom((state) => state + 1) // void (also set the value)
atom() // 6
const derivedAtom = create(get => get(atom) * 2)

Actions

With the second argument, you can specify actions for your atoms. use function is used to grab these actions.

import { create, use } from 'xoid'
const counterAtom = create(3, (atom) => ({
increment: () => atom((s) => s + 1),
incrementBy: (by) => atom((s) => s + by)
}))
use(counterAtom).incrementBy(5)
setInterval(use(counterAtom).increment, 1000)

React integration

xoid has a minimal React integration. No need for wrapping components into context providers. Just import useAtom and start using!

import { create, subscribe, use } from 'xoid'
import { useAtom } from '@xoid/react'
// in a React component
const count = useAtom(counterAtom)
const { increment } = use(counterAtom)
// outside React
const unsubscribe = subscribe(alpha, console.log)

No more hand-written reducers!

use function, when used with a second argument, acts as a selector. The selected node will be a subscribable getter/setter object like any other atom. xoid is based on immutable updates, so if you "surgically" set state of a selected branch, changes will propagate to the root.

import { create, use } from 'xoid'
const atom = create({ deeply: { nested: { foo: 5 } } })
const fooAtom = use(atom, (s) => s.deeply.nested.foo)
const oldValue = atom()
fooAtom(25) // set the value surgically into the store
const newValue = atom()
console.log(newValue) // { deeply: { nested: { foo: 25 } } }
assert(oldValue !== newValue) // โœ…

No-API Finite State Machines!

No additional syntax is required to define and use finite state machines. Just use the second argument of the callback as the state transition function.

import { create } from 'xoid'
const red = { color: '#f00', onClick: () => machine(green) }
const green = { color: '#0f0', onClick: () => machine(red) }
const machine = create(red)
// in a React component
const { color, onClick } = useAtom(machine)
return <div style={{ color }} onClick={onClick}/>
  • Easy to learn
  • Small bundle size
  • Zero configuration
  • Framework-agnostic
  • Computed values
  • Async actions
  • Transient updates
  • Local & global state
  • Finite state machines
  • Extensive Typescript support
  • Devtools