Skip to main content

Framework-agnostic state management library designed for simplicity and scalability

Small

It's easy-to-learn, has no external dependencies, and it's only 1.1kB minified and gzipped.

Robust

It's based on immutable updates and explicit subscriptions. This makes it ideal for teams.

Well-documented

Extensively documented, including a rich "Recipes" section and examples.

Simple primitives

xoid is based on atoms. Atoms are holders of state. atom function is used to create them.

import { atom } from 'xoid'

const $count = atom(3)

$count.set(5)
$count.update((state) => state + 1)
console.log($count.value) // 6

Actions

With the second argument, you can define actions for your atoms.

import { atom } from 'xoid'

const $count = atom(3, (atom) => ({
increment: () => atom.update((s) => s + 1),
incrementBy: (by) => atom.update((s) => s + by)
}))

$count.actions.incrementBy(5)

Computed Values

It has a Recoil-inspired API for derived atoms. Alternatively, the .map method can be used.

import { atom } from 'xoid'

const $doubleCount = atom((get) => get($count) * 2)

const $tripleCount = $count.map((state) => state * 3)

Framework Integrations

xoid has React, Vue, and Svelte integrations. It can be used without any framework as well.

import { atom } from 'xoid'
import { useAtom } from '@xoid/react'
// @xoid/vue and @xoid/svelte packages are used the same way

// in a component
const count = useAtom($count)
const { increment } = $count.actions

// vanilla JavaScript
const unsubscribe = $count.subscribe(console.log)

No more hand-written reducers!

There's the .focus method, which can be used as a selector/lens. xoid is based on immutable updates, so if you "surgically" set state of a focused branch, changes will propagate to the root.

import { atom } from 'xoid'

const $atom = atom({ deeply: { nested: { alpha: 5 } } })
const previousValue = atom.value

// select `.deeply.nested.alpha`
const $alpha = $atom.focus((s) => s.deeply.nested.alpha)
$alpha.update((s) => s + 1)

// root state is replaced with new immutable state
assert($atom.value !== previousValue) // ✅

No-API Finite State Machines!

Atoms are potent primitives. No additional syntax is required for expressing finite state machines.

import { atom } from 'xoid'

const red = { color: '#f00', onClick: () => machine.set(green) }
const green = { color: '#0f0', onClick: () => machine.set(red) }
const $machine = atom(red)

// in a 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