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.
-
Simple and powerful abstractions
Only a few core primitives:atom
andcomputed
,action
andeffect
. 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 nativeawait
andAbortController
. -
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
Type inference is a top priority with excellent type safety throughout.
npm install @reatom/core@alpha @reatom/react@alpha
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>
))
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
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
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 help organize complex operations:
import { atom } from '@reatom/core'
export const list = atom([], 'list')
.extend((target) => ({
isLoading: atom(false, `${target.name}.isLoading`),
}))
.actions((target) => ({
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())
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
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>
)
})
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>
})
For a fast start, use our template with React and Mantine:
- Getting Started - Learn the basics
- Guides - Advanced use cases
- Reference - Complete API documentation
- Handbook - In-depth patterns and concepts
We welcome contributions! See CONTRIBUTING.md for guidelines.
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