Skip to main content

Quick Tutorial

You can skip this part if you've already read the Github README.


Atoms are holders of state.

import create from 'xoid' // or: import { create } from 'xoid'

const $count = create(3)
console.log($count.value) // 3
$count.update((state) => state + 1)
console.log($count.value) // 6

Atoms may have actions.

import create from 'xoid'

const $count = create(5, (atom) => ({
increment: () => atom.update(s => s + 1),
decrement: () => atom.value-- // `.value` setter is supported too


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 create from 'xoid'

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

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

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

Derived state

State can be derived from other atoms. This API was heavily inspired by Recoil.

const $alpha = create(3)
const $beta = create(5)
// derived atom
const $sum = create((read) => read($alpha) + read($beta))

Alternatively, .map method can be used to quickly derive the state from a single atom.

const $alpha = create(3)
// derived atom
const $doubleAlpha = $ => s * 2)

Atoms are lazily evaluated. This means that the callback functions of $sum and $doubleAlpha in this example won't execute until the first subscription to these atoms. This is a performance optimization.


For subscriptions, subscribe and watch are used. They are the same, except watch runs the callback immediately, while subscribe waits for the first update after subscription.

const unsub = $atom.subscribe((state, previousState) => {
console.log(state, previousState)

// later

All methods of a xoid atom are covered up to this point. This concludes the basic usage! 🎉