Reatom
Reatom is the ultimate logic and state manager for small widgets and huge SPAs.
A powerful reactive state management library designed to become your go-to resource for building anything from tiny libraries to full-blown applications.
Key Features
Simple and powerful abstractions
Only a few core primitives:atomandcomputed,actionandeffect. All other features work on top of that.Explicit reactivity without proxies
Direct, predictable state management with atomization patterns for maximum performance.Perfect effects management
Advanced async handling with caching, retrying, and automatic cancellation using nativeawaitandAbortController.Excellent debugging experience
Built-in logging and immutable cause tracking for complex async flows.Composable extensions
Enhance atoms and actions with ready-made solutions for async operations, persistence, caching, and more.Framework-agnostic
Adapters for many frameworks and libraries.Smallest bundle size
2 KB gzipped for core.Best TypeScript experience
Top type inference with excellent type safety throughout.
Installation
npm install @reatom/core @reatom/react
Quick Start
Basic Example
import { atom, computed } from '@reatom/core'
import { reatomComponent } from '@reatom/react'
const counter = atom(0)
const isEven = computed(() => counter() % 2 === 0)
const Counter = reatomComponent(() => (
<section>
<p>
{counter()} is {isEven() ? 'even' : 'odd'}
</p>
<button onClick={() => counter.set(v => v + 1)}>Increment</button>
</section>
))
Core Primitives
Atom
The base state container:
import { atom } from '@reatom/core'
const counter = atom(0)
console.log(counter()) // 0
counter.set(1)
console.log(counter()) // 1
counter.set((state) => state + 5)
console.log(counter()) // 6
Computed
Lazy memoized computations:
import { atom, computed } from '@reatom/core'
const counter = atom(0)
const isEven = computed(() => counter() % 2 === 0)
console.log(isEven()) // true
counter.set(1)
console.log(isEven()) // false
Effect
React to state changes immediately:
import { atom, computed, effect } from '@reatom/core'
const counter = atom(0)
const isEven = computed(() => counter() % 2 === 0)
effect(() => {
console.log(`${counter()} is ${isEven() ? 'even' : 'odd'}`)
})
Actions and Organization
Actions help organize complex operations:
import { atom } from '@reatom/core'
export const list = atom([], 'list').extend((target) => ({
isLoading: atom(false, `${target.name}.isLoading`),
async load(page: number) {
target.isLoading.set(true)
const response = await fetch(`/api/list?page=${page}`)
const payload = await response.json()
target.set(payload)
target.isLoading.set(false)
},
}))
list.load(1)
console.log(list.isLoading())
Extensions
Enhance atoms and actions with composable extensions:
import { atom, computed, withAsyncData, withSearchParams } from '@reatom/core'
const search = atom('', 'search').extend(withSearchParams('search'))
const page = atom(1, 'page').extend(withSearchParams('page'))
const listResource = computed(async () => {
const response = await fetch(`/api/data?search=${search()}&page=${page()}`)
return await response.json()
}, 'listResource').extend(withAsyncData({ initState: [] }))
listResource.ready() // false during fetch
listResource.data() // the fetch result
listResource.error() // Error or undefined
Forms
Type-safe form management:
import { reatomForm } from '@reatom/core'
const loginForm = reatomForm(
{
username: '',
password: '',
passwordDouble: '',
},
{
validate({ password, passwordDouble }) {
if (password !== passwordDouble) {
return 'Passwords do not match'
}
},
onSubmit: async (values) => {
return await api.login(values)
},
validateOnBlur: true,
name: 'loginForm',
},
)
Using in React:
import { reatomComponent, bindField } from '@reatom/react'
const LoginForm = reatomComponent(() => {
const { submit, fields } = loginForm
return (
<form
onSubmit={(e) => {
e.preventDefault()
loginForm.submit()
}}
>
<input {...bindField(fields.username)} />
<input {...bindField(fields.password)} type="password" />
<input {...bindField(fields.passwordDouble)} type="password" />
<button type="submit" disabled={!submit.ready()}>
Login
</button>
</form>
)
})
Routing
Manage routes and state lifecycles:
import { reatomRoute, reatomForm } from '@reatom/core'
export const loginRoute = reatomRoute({
path: '/login',
async loader() {
const loginForm = reatomForm(
{ username: '', password: '' },
{
onSubmit: async (values) => await api.login(values),
name: 'loginForm',
},
)
return { loginForm }
},
})
const LoginPage = reatomComponent(() => {
if (!loginRoute.loader.ready()) return <div>Loading...</div>
const { loginForm } = loginRoute.loader.data()
return <form>{/* your form */}</form>
})
Template
For a fast start, use our template with React and Mantine:
Documentation
- Getting Started - Learn the basics
- Guides - Advanced use cases
- Reference - Complete API documentation
- Handbook - In-depth patterns and concepts
Community
Contributing
We welcome contributions! See CONTRIBUTING.md for guidelines.
License
Credits
Special thanks to:
- React, Redux, Effector, and $mol for inspiration
- Quokka and vitest for testing experience
- Astro for documentation framework
- Vercel for hosting and CI/CD
- All our contributors and maintainers
Good primitive is more than a framework