Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/reatom/reatom/llms.txt

Use this file to discover all available pages before exploring further.

Quick Start

This guide will walk you through building a simple counter application with Reatom and React. You’ll learn the core concepts while creating a working example.

Prerequisites

Make sure you have Reatom installed:
npm install @reatom/core @reatom/react
See the Installation guide for other package managers.

Building a Counter

Let’s build a counter app step by step to understand Reatom’s core primitives.
1

Create an atom for the counter state

An atom is the base state container in Reatom. It holds a single value that can be read and updated.
import { atom } from '@reatom/core'

const counter = atom(0)
You can read and update atoms directly:
// Read the atom state
console.log(counter()) // 0

// Write a new state to the atom
counter.set(1)
console.log(counter()) // 1

// Update using a function
counter.set((state) => state + 5)
console.log(counter()) // 6
2

Create a computed value

A computed creates lazy memoized computations that automatically update when dependencies change.
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
Computed values are lazy - they only recalculate when accessed and their dependencies have changed.
3

Create the Counter component

Use reatomComponent to create a reactive React component that automatically subscribes to atoms.
Counter.tsx
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>
))

export default Counter
The coolest thing about reatomComponent is that you can use reactive states (atoms) in any order without the rules of hooks!
4

Add the component to your app

Import and use your Counter component like any other React component:
App.tsx
import Counter from './Counter'

function App() {
  return (
    <div className="App">
      <h1>My Counter App</h1>
      <Counter />
    </div>
  )
}

export default App

Complete Example

Here’s the full counter example with all the code together:
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>
))

export default Counter

Understanding Effects

Effects let you react to state changes immediately. They’re similar to computed but run automatically after creation.
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'}`)
})

// This will log: "0 is even"

counter.set(1)
// This will log: "1 is odd"
Effects are perfect for running long-lived processes like API polling or timers that work independently of the UI.

Organizing with Actions

As your app grows, you can organize complex operations using actions with the extend method:
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())

Real-World Example: Search with Async Data

Here’s a more complex example from the Reatom source code showing async data handling:
import { atom, computed, withAsyncData, sleep, wrap } from '@reatom/core'
import { searchIssues } from './api'

export const issueQuery = atom('', 'issueQuery')
export const issuePage = atom(0, 'issuePage')
export const issuePerPage = atom(10, 'issuePerPage')

export const issuesResource = computed(async () => {
  const query = issueQuery()

  if (!query) {
    return {
      items: [],
      total_count: 0,
      incomplete_results: false,
    }
  }

  // Debounce the search
  await wrap(sleep(250))

  const filters = {
    query,
    page: issuePage(),
    perPage: issuePerPage(),
  }

  return searchIssues(filters)
}, 'issuesResource').extend(withAsyncData())

export const isIssuesLoading = computed(
  () => !issuesResource.ready(),
  'isIssuesLoading',
)
export const issuesError = issuesResource.error
The withAsyncData extension adds helpful properties like ready(), data(), and error() to track async operations.

Next Steps

Now that you’ve built your first Reatom application, explore these topics:

Core Concepts: Atoms

Deep dive into atoms and state management

Core Concepts: Computed

Master lazy memoized computations

Core Concepts: Effects

Learn about reactive side effects

Async Operations

Handle async data and API calls

Try the Template

Want to see a full-featured example? Check out the official React template with search, filtering, and pagination: Open in StackBlitz