Skip to content

Package @reatom/methods

Method is special API which works only in Reatom context frame, like action or atom. Some methods are reactive and may work only in reactive context (in atom). Some methods are isomorphic and can be used both in reactive and non-reactive context. Some methods may change the type of context, like peek for none reactive atom reading or wrap for context binding.

Classes

AbortVariable

Defined in: packages/core/src/methods/abortVar.ts:43

Interface for context variables in Reatom

Variables maintain values within the context of a computation tree, allowing for context-aware state similar to React’s Context API but with more granular control and integration with Reatom’s reactive system.

See

https://github.com/tc39/proposal-async-context?tab=readme-ov-file#asynccontextvariable

Extends

Constructors

Constructor

new AbortVariable(): AbortVariable

Defined in: packages/core/src/methods/abortVar.ts:63

Returns

AbortVariable

Overrides

Variable.constructor

Properties

_findReactiveStartIndex

protected _findReactiveStartIndex: number = 1

Defined in: packages/core/src/methods/abortVar.ts:47

Overrides

Variable._findReactiveStartIndex

create()

protected create: (…params) => ReatomAbortController

Defined in: packages/core/src/methods/variable.ts:30

Parameters
params

…[AbortController?]

Returns

ReatomAbortController

Inherited from

Variable.create

name

readonly name: `var#${string}`

Defined in: packages/core/src/methods/variable.ts:32

Inherited from

Variable.name

run

run: GenericAction<<Params, Payload>(value, cb, …params) => Payload>

Defined in: packages/core/src/methods/variable.ts:97

Executes a callback function with the variable set to a specific value within that execution context

This method creates a new frame in the context tree where the variable is bound to the provided value. The callback function runs within this frame, allowing any code inside (and its descendants) to access this value via get().

Example
const userVar = variable<string>('user')
userVar.run('Alice', () => {
console.log(userVar.get()) // 'Alice'
})
// Passing parameters to callback
const result = userVar.run('Bob', (x, y) => x + y, 2, 3)
console.log(result) // 5
Template

Types of parameters passed to the callback

Template

Return type of the callback

Param

The value to set for this variable during callback execution. Cannot be undefined.

Param

The callback function to execute with the variable set

Param

Additional parameters to pass to the callback

Returns

The return value of the callback

Throws

If value is undefined

Inherited from

Variable.run

spawn

spawn: GenericAction<<Params, Payload>(cb, …params) => Payload>

Defined in: packages/core/src/methods/variable.ts:122

This utility allow you to start a function which will NOT follow the async context of this variable.

Example
// If you want to start a fetch when the atom gets a subscription,
// but don't want to abort the fetch when the subscription is lost to save the data anyway.
const some = atom('...').extend(
withConnectHook((target) => {
abortVar.spawn(async () => {
// here `wrap` doesn't follow the connection abort
const data = await wrap(api.getSome())
some(data)
})
}),
)
Inherited from

Variable.spawn

Methods

find()

find<Result>(cb?, frame?): undefined | Result

Defined in: packages/core/src/methods/abortVar.ts:49

Traverses the frame tree to find and map the variable value.

Type Parameters
Result

Result = ReatomAbortController

Return type of the callback

Parameters
cb?

(payload) => undefined | Result

Optional transformation callback

frame?

Frame<any, any[], any>

Optional frame to check (defaults to current top frame)

Returns

undefined | Result

The transformed value or undefined if not found

Overrides

Variable.find

first()

first(frame): undefined | ReatomAbortController

Defined in: packages/core/src/methods/variable.ts:139

Gets the variable value from the first frame only, without traversing the whole frame tree

Unlike get() which searches through parent frames, this method only checks the top frame. Returns undefined if the variable is not set in the frame.

Parameters
frame

Frame<any, any[], any> = ...

Returns

undefined | ReatomAbortController

The value in the frame, or undefined if not set

Inherited from

Variable.first

get()

get(frame?): undefined | ReatomAbortController

Defined in: packages/core/src/methods/variable.ts:63

Gets the passed frame value of the variable

Parameters
frame?

Frame<any, any[], any>

Optional frame to check (defaults to current top frame)

Returns

undefined | ReatomAbortController

The current value

Throws

If the variable is not found in the frame tree

Inherited from

Variable.get

has()

has(frame?): boolean

Defined in: packages/core/src/methods/variable.ts:150

Checks if the variable exists in the passed frame stack

Parameters
frame?

Frame<any, any[], any>

Optional frame to check (defaults to current top frame)

Returns

boolean

True if the variable exists in the context

Inherited from

Variable.has

set()

set(…params): ReatomAbortController

Defined in: packages/core/src/methods/variable.ts:195

Sets a new variable value for CURRENT frame. Be aware that it is mostly for internal use!

Parameters
params

…[AbortController?]

Parameters passed to the setter function

Returns

ReatomAbortController

The new value

Inherited from

Variable.set

subscribe()

subscribe(cb?): AbortSubscription

Defined in: packages/core/src/methods/abortVar.ts:122

Subscribes to abortion events from parent context tree (including current frame).

Creates a subscription that listens for abort signals from any parent AbortController in the context tree. When an abort occurs, the callback is invoked with the abort error and the subscription automatically cleans up.

It is IMPORTANT to clean up the subscription when it is no longer needed, otherwise a memory leak will occur. You can use the unsubscribe function returned by this method or using statement.

Parameters
cb?

(error) => void

Callback invoked when abortion occurs

Returns

AbortSubscription

Subscription object

Examples
const myResource = computed(async () => {
const { controller, unsubscribe } = abortVar.subscribe()
const { signal } = controller
try {
const response = await fetch('/api/my-resource', { signal })
return await response.json()
} finally {
unsubscribe()
}
}).extend(withAsyncData())
const myResource = computed(async () => {
using { controller } = abortVar.subscribe()
const { signal } = controller
const response = await fetch('/api/my-resource', { signal })
return await response.json()
}).extend(withAsyncData())
throwIfAborted()

throwIfAborted(): void

Defined in: packages/core/src/methods/abortVar.ts:174

NOTE: this method already used in wrap, that you should use in your code instead.

Throws if any AbortController in the parent context (frame) tree, including the current frame, is aborted.

Returns

void

Throws

ReatomAbortController

Defined in: packages/core/src/methods/abortVar.ts:16

Version of abort controller with explicit name for better debugging.

May control variable propagation by setting the spawned flag (used internally to handle abort boundaries).

Param

The name of the abort controller

Param

Whether to traverse the frame tree beyond the current frame (default: false)

Extends

  • AbortController

Constructors

Constructor

new ReatomAbortController(name, spawned): ReatomAbortController

Defined in: packages/core/src/methods/abortVar.ts:17

Parameters
name

string

spawned

boolean = false

Returns

ReatomAbortController

Overrides

AbortController.constructor

Properties

name

name: string

Defined in: packages/core/src/methods/abortVar.ts:18

signal

readonly signal: AbortSignal

Defined in: node_modules/.pnpm/typescript@5.9.3/node_modules/typescript/lib/lib.dom.d.ts:2723

The signal read-only property of the AbortController interface returns an AbortSignal object instance, which can be used to communicate with/abort an asynchronous operation as desired.

MDN Reference

Inherited from

AbortController.signal

spawned

spawned: boolean = false

Defined in: packages/core/src/methods/abortVar.ts:19

Methods

abort()

abort(reason?): void

Defined in: packages/core/src/methods/abortVar.ts:23

The abort() method of the AbortController interface aborts an asynchronous operation before it has completed.

MDN Reference

Parameters
reason?

any

Returns

void

Overrides

AbortController.abort


Variable<T, Params>

Defined in: packages/core/src/methods/variable.ts:27

Interface for context variables in Reatom

Variables maintain values within the context of a computation tree, allowing for context-aware state similar to React’s Context API but with more granular control and integration with Reatom’s reactive system.

See

https://github.com/tc39/proposal-async-context?tab=readme-ov-file#asynccontextvariable

Extended by

Type Parameters

T

T extends NonUndefined

Type of the stored value

Params

Params extends any[] = any[]

Constructors

Constructor

new Variable<T, Params>(options?): Variable<T, Params>

Defined in: packages/core/src/methods/variable.ts:34

Parameters
options?

AsyncVariableOptions<T, Params>

Returns

Variable<T, Params>

Properties

_findReactiveStartIndex

protected _findReactiveStartIndex: number = 0

Defined in: packages/core/src/methods/variable.ts:28

create()

protected create: (…params) => T

Defined in: packages/core/src/methods/variable.ts:30

Parameters
params

Params

Returns

T

name

readonly name: `var#${string}`

Defined in: packages/core/src/methods/variable.ts:32

run

run: GenericAction<<Params, Payload>(value, cb, …params) => Payload>

Defined in: packages/core/src/methods/variable.ts:97

Executes a callback function with the variable set to a specific value within that execution context

This method creates a new frame in the context tree where the variable is bound to the provided value. The callback function runs within this frame, allowing any code inside (and its descendants) to access this value via get().

Example
const userVar = variable<string>('user')
userVar.run('Alice', () => {
console.log(userVar.get()) // 'Alice'
})
// Passing parameters to callback
const result = userVar.run('Bob', (x, y) => x + y, 2, 3)
console.log(result) // 5
Template

Types of parameters passed to the callback

Template

Return type of the callback

Param

The value to set for this variable during callback execution. Cannot be undefined.

Param

The callback function to execute with the variable set

Param

Additional parameters to pass to the callback

Returns

The return value of the callback

Throws

If value is undefined

spawn

spawn: GenericAction<<Params, Payload>(cb, …params) => Payload>

Defined in: packages/core/src/methods/variable.ts:122

This utility allow you to start a function which will NOT follow the async context of this variable.

Example
// If you want to start a fetch when the atom gets a subscription,
// but don't want to abort the fetch when the subscription is lost to save the data anyway.
const some = atom('...').extend(
withConnectHook((target) => {
abortVar.spawn(async () => {
// here `wrap` doesn't follow the connection abort
const data = await wrap(api.getSome())
some(data)
})
}),
)

Methods

find()

find<Result>(cb?, frame?): undefined | Result

Defined in: packages/core/src/methods/variable.ts:165

Traverses the frame tree to find and map the variable value.

Type Parameters
Result

Result = T

Return type of the callback

Parameters
cb?

(payload) => undefined | Result

Optional transformation callback

frame?

Frame<any, any[], any> = ...

Optional frame to check (defaults to current top frame)

Returns

undefined | Result

The transformed value or undefined if not found

first()

first(frame): undefined | T

Defined in: packages/core/src/methods/variable.ts:139

Gets the variable value from the first frame only, without traversing the whole frame tree

Unlike get() which searches through parent frames, this method only checks the top frame. Returns undefined if the variable is not set in the frame.

Parameters
frame

Frame<any, any[], any> = ...

Returns

undefined | T

The value in the frame, or undefined if not set

get()

get(frame?): undefined | T

Defined in: packages/core/src/methods/variable.ts:63

Gets the passed frame value of the variable

Parameters
frame?

Frame<any, any[], any>

Optional frame to check (defaults to current top frame)

Returns

undefined | T

The current value

Throws

If the variable is not found in the frame tree

has()

has(frame?): boolean

Defined in: packages/core/src/methods/variable.ts:150

Checks if the variable exists in the passed frame stack

Parameters
frame?

Frame<any, any[], any>

Optional frame to check (defaults to current top frame)

Returns

boolean

True if the variable exists in the context

set()

set(…params): T

Defined in: packages/core/src/methods/variable.ts:195

Sets a new variable value for CURRENT frame. Be aware that it is mostly for internal use!

Parameters
params

Params

Parameters passed to the setter function

Returns

T

The new value

Interfaces

AbortSubscription

Defined in: packages/core/src/methods/abortVar.ts:30

Properties

[asyncDispose]

[asyncDispose]: Unsubscribe

Defined in: packages/core/src/methods/abortVar.ts:34

[dispose]

[dispose]: Unsubscribe

Defined in: packages/core/src/methods/abortVar.ts:33

controller

controller: ReatomAbortController

Defined in: packages/core/src/methods/abortVar.ts:31

unsubscribe

unsubscribe: Unsubscribe

Defined in: packages/core/src/methods/abortVar.ts:32


AsyncVariableOptions<T, Params>

Defined in: packages/core/src/methods/variable.ts:8

Type Parameters

T

T extends NonUndefined

Params

Params extends any[] = any[]

Properties

create()?

optional create: (…params) => T

Defined in: packages/core/src/methods/variable.ts:14

Parameters
params

Params

Returns

T

defaultValue?

optional defaultValue: T

Defined in: packages/core/src/methods/variable.ts:13

name?

optional name: string

Defined in: packages/core/src/methods/variable.ts:12


Effect()<State>

Defined in: packages/core/src/methods/effect.ts:10

Derived state container.

A computed atom automatically tracks dependencies and recalculates only when those dependencies change. The calculation is performed lazily, only when the computed value is read AND subscribed to.

Extends

Type Parameters

State

State

The type of derived state

Effect(…params): State

Defined in: packages/core/src/methods/effect.ts:10

Derived state container.

A computed atom automatically tracks dependencies and recalculates only when those dependencies change. The calculation is performed lazily, only when the computed value is read AND subscribed to.

Parameters

params

…[]

Parameters to pass to the atom

Returns

State

The atom’s payload (typically its current state)

Properties

__reatom

__reatom: AtomMeta

Defined in: packages/core/src/core/atom.ts:106

Reference to the atom’s internal metadata.

Inherited from

Computed.__reatom

actions

actions: Actions<Effect<State>>

Defined in: packages/core/src/core/atom.ts:86

Bind methods to the atom to extend its functionality.

Deprecated

Use extend instead

Inherited from

Computed.actions

extend

extend: Extend<Effect<State>>

Defined in: packages/core/src/core/atom.ts:92

Extension system to add capabilities to atoms. Allows adding middleware, methods, or other functionality to modify atom behavior.

Inherited from

Computed.extend

set

set: unknown

Defined in: packages/core/src/core/atom.ts:79

Inherited from

Computed.set

subscribe()

subscribe: (cb?) => Unsubscribe

Defined in: packages/core/src/core/atom.ts:103

Subscribe to state changes, with the first call happening immediately. When a subscriber is added, the callback is immediately invoked with the current state. After that, it’s called whenever the atom’s state changes.

Parameters
cb?

(state) => any

Callback function that receives the atom’s state when it changes

Returns

Unsubscribe

An unsubscribe function that removes the subscription when called

Inherited from

Computed.subscribe

unsubscribe

unsubscribe: Unsubscribe

Defined in: packages/core/src/methods/effect.ts:11

Type Aliases

Deatomize<T>

Deatomize<T> = T extends LinkedListLikeAtom<infer T> ? T extends LinkedList<LLNode<infer T>> ? Deatomize<T>[] : never : T extends AtomLike<infer T, infer Params, infer Payload> ? T extends AtomLike<ActionState<Params, Payload>, Params, Payload> ? T : Deatomize<T> : T extends Map<infer K, infer T> ? Map<K, Deatomize<T>> : T extends Set<infer T> ? Set<Deatomize<T>> : T extends infer T[] ? Deatomize<T>[] : T extends Primitive | Builtin ? T : T extends Record<PropertyKey, unknown> ? { [K in keyof T]: Deatomize<T[K]> } : T

Defined in: packages/core/src/methods/deatomize.ts:27

Type utility that recursively unwraps atom types to their state types

This complex type recursively traverses a type structure, unwrapping atoms to their contained state types. It handles various container types like arrays, maps, sets, and objects.

Type Parameters

T

T

The type to unwrap

Returns

Unwrapped version of the type with atoms replaced by their state types


FunctionSource

FunctionSource = string

Defined in: packages/core/src/methods/memo.ts:33

Type representing the source of a function as a string. Used for caching and identification purposes.

Variables

abortVar

abortVar: AbortVariable

Defined in: packages/core/src/methods/abortVar.ts:209

Global abort variable that precess AbortController’s coupled to the current frame stack.

The abortVar is computed from all other abort atoms in the current frame tree, which allows for propagation of abortion signals through the computation hierarchy. This is a critical component for cancellation handling in Reatom’s async operations.

Examples

// Trigger abortion of the current frame
abortVar.abortCurrent('Operation cancelled')
// Trigger abortion of the current frame stack
abortVar.get()?.abort('Operation cancelled')
// Check if current operation (the whole frame stack) is aborted
abortVar.throwIfAborted()
// continue operation...
// Get AbortController for fetch API
const { controller, unsubscribe } = abortVar.subscribe()
await fetch('/api/data', { signal: controller.signal })
unsubscribe()

log

log: Action<any[], any>

Defined in: packages/core/src/methods/connectLogger.ts:74

A special logging action for debugging Reatom applications.

log provides an enhanced logging experience with automatic tracing and production-safe output. It forwards all arguments to the native console.log while providing additional context about the call stack and dependencies.

Key Benefits

  • Short and handy name - Easy to type and use throughout your codebase
  • Automatic stack tracing - Shows the relative call stack each time it’s called
  • Use it everywhere - Logs are only visible when connectLogger() is active
  • Production-safe - Logs won’t appear in production builds when logger is not connected
  • Context-aware - Integrates with Reatom’s dependency tracking system
  • Extendable - You can extend it with other extensions to add custom behavior

Examples

import { log } from '@reatom/core'
// Make LOG available globally (recommended)
declare global {
var LOG: typeof log
}
globalThis.LOG = log
// Use anywhere in your code
const myAtom = atom((ctx) => {
const value = ctx.spy(someAtom)
LOG('Current value:', value)
return value * 2
})
// In actions
const myAction = action((ctx, payload) => {
LOG('Action called with:', payload)
// ... action logic
})
// Multiple arguments like console.log
LOG('Debug info:', { foo: 'bar' }, [1, 2, 3])
// Extend LOG with custom behavior using withCallHook
import { withCallHook } from '@reatom/core'
LOG.extend(
withCallHook((ctx, params) => {
// Send logs to a remote service
sendToAnalytics({ level: 'debug', args: params })
}),
)

See

connectLogger - Must be called to enable logging output


parseAtoms()

parseAtoms: <Value>(value) => Deatomize<Value> = deatomize

Defined in: packages/core/src/methods/deatomize.ts:113

Recursively unwraps atoms in a value to get their current states

This function deeply traverses a value, including nested objects, arrays, maps, and sets, replacing atoms with their current state values. It’s useful for serialization, debugging, or creating snapshots of state that don’t contain reactive references.

Type Parameters

Value

Value

The type of value to parse

Parameters

value

Value

The value containing atoms to unwrap

Returns

Deatomize<Value>

A new value with all atoms replaced by their current states

Example

const user = {
id: 42,
name: atom('John', 'userName'),
stats: {
score: atom(100, 'userScore'),
badges: atom(['gold', 'silver'], 'userBadges'),
},
}
// Results in: { id: 42, name: 'John', stats: { score: 100, badges: ['gold', 'silver'] }}
const plainUser = deatomize(user)

Deprecated

Use deatomize instead


reatomObservable()

const reatomObservable: {<T>(producer, init?, name?): Atom<undefined | T>; <T>(producer, init, name?): Atom<T>; }

Defined in: packages/core/src/methods/reatomObservable.ts:133

Creates a Reatom atom from an observable-like data source.

This function bridges external observable sources (like RxJS observables, event emitters, or custom observable implementations) with Reatom’s reactive system. The atom will automatically subscribe to the observable when it gains subscribers and unsubscribe when it loses all subscribers.

Call Signature

<T>(producer, init?, name?): Atom<undefined | T>

Type Parameters
T

T

Parameters
producer

Producer<T>

init?

undefined

name?

string

Returns

Atom<undefined | T>

Call Signature

<T>(producer, init, name?): Atom<T>

Type Parameters
T

T

Parameters
producer

Producer<T>

init

T | () => T

name?

string

Returns

Atom<T>

Examples

// With RxJS Observable
import { interval } from 'rxjs'
const timerAtom = reatomObservable(interval(1000))
// With custom observable function
const customAtom = reatomObservable((setter) => {
const id = setInterval(() => setter(Date.now()), 1000)
return () => clearInterval(id)
})
// With MobX observable
import { autorun, observable } from 'mobx'
const mobxStore = observable({ count: 0 })
const atomWithDefault = reatomObservable(
() => autorun(() => mobxStore.count),
() => mobxStore.count,
)
// With addEventListener
const clickAtom = reatomObservable((setter) => {
document.addEventListener('click', setter)
return () => document.removeEventListener('click', setter)
})

Template

The type of values emitted by the observable

Param

Either a function that accepts a setter callback and returns an unsubscribe function, or an object with a subscribe method

Param

Optional initial value or function that returns the initial value. If not provided, the atom starts with undefined

Returns

A Reatom atom that reflects the observable’s values


retryComputed()

const retryComputed: {(target): never; <T>(target): T; }

Defined in: packages/core/src/methods/retry.ts:38

Retries computed atom by resetting its dependencies and re-evaluating the computed function .

Call Signature

(target): never

Parameters
target

Action

Returns

never

Call Signature

<T>(target): T

Type Parameters
T

T

Parameters
target

AtomLike<any, any, T>

Returns

T

Template

The return type of the atom.

Param

The atom to retry.

Returns

The result of the atom after retrying.

Throws

If the target is not an action.


rollback

rollback: Action<[any], void>

Defined in: packages/core/src/methods/transaction.ts:107


select()

select: <State>(cb, equal, key?) => State = memo

Defined in: packages/core/src/methods/memo.ts:162

Memoize additional computation inside a different calls of an atom (computed or an effect) or an action.

It’s useful when you want to avoid recomputing of the whole computed function, especially if the computation is expensive. You could create an external atom by yourself, but it is not handy sometimes.

The memo function takes a callback function cb that returns the value to be memoized, an optional equal function that compares the new and old values to determine if the memoized value should be updated, and an optional key to uniquely identify the memoized value.

Important note: The created internal atom only uses the first passed callback function. This means it’s unsafe to rely on data from the closure that changes on every recall, as subsequent calls will not update the callback used by the internal atom.

Note for rare cases: A created underhood atom is memorized for each memo by the passed function sources from “toString()” method, so every computed callback in different memos of the same atom should contain different code. However, you can provide a custom key parameter to uniquely identify different memo calls instead of relying on toString().

When a custom key is provided, the toString() duplication check is bypassed, allowing you to use the same callback function multiple times within the same atom by providing different keys for each usage.

Type Parameters

State

State

Parameters

cb

A function that returns the value to be selected and memoized.

() => State | (state?) => State

equal

(newState, oldState) => boolean

key?

string

An optional unique identifier for the memoized value. Defaults to cb.toString(). Used to distinguish between different memo calls within the same computed function. Providing a custom key is recommended when using similar callback functions to avoid conflicts.

Returns

State

The memoized value.

Examples

// This is very useful to memoize not just the end string,
// but, for example, a template computation inside `reatomComponent` or so on.
export const listSum = computed(() => {
// Simple call of `list().length` will cause extra recomputations for elements sorting or its internal changes.
// correct optimal way, the component will rerender only on `length` change
const length = memo(() => list().length)
// you could call different `memo` many times in one computed
const sum = memo(() => list().reduce((acc, el) => acc + el().value, 0))
return `The sum of ${length} elements is: ${sum}`
}, 'listSum')
// An example of using the equality function as part of the logic
const scroll = atom(0, 'scroll')
const throttledScroll = computed(() => {
const { state } = memo(
() => ({ state: scroll(), time: Date.now() }),
// Only update if 50ms have passed since the last update
(next, prev) => prev.time + 50 < Date.now(),
)
return state
}, 'throttledScroll')
// Using memo in actions for expensive computations
const processData = action((data: string[]) => {
// You can even create a service, but not one that is tied only to this action.
const myService = memo(() => new Service())
myService.send(data)
}, 'processData')

Deprecated

Use memo instead


spawn

spawn: AbortVariable["spawn"]

Defined in: packages/core/src/methods/abortVar.ts:212

Deprecated

Use abortVar.spawn instead


transactionVar

transactionVar: TransactionVariable

Defined in: packages/core/src/methods/transaction.ts:105


variable()

variable: {<T>(name?): Variable<T, [T]>; <Params, Payload>(set, name?): Variable<Payload, Params>; }

Defined in: packages/core/src/methods/variable.ts:235

Creates a new context variable with getter and setter functionality

This implementation provides a similar capability to the proposed TC39 AsyncContextVariable, allowing you to maintain values that are specific to a particular execution context. Variables created with this function can be accessed and modified within their frame context.

Call Signature

<T>(name?): Variable<T, [T]>

Type Parameters
T

T extends NonUndefined

Parameters
name?

string

Returns

Variable<T, [T]>

Call Signature

<Params, Payload>(set, name?): Variable<Payload, Params>

Type Parameters
Params

Params extends any[]

Payload

Payload extends NonUndefined

Parameters
set

(…params) => Payload

name?

string

Returns

Variable<Payload, Params>

Example

// Simple variable with string values
const currentUser = variable<string>('currentUser')
// Set the value
currentUser.set('Alice')
// Get the value
console.log(currentUser.get()) // 'Alice'
// Run code with a different value
currentUser.run('Bob', () => {
console.log(currentUser.get()) // 'Bob'
})
// Advanced variable with custom setter logic
const userRole = variable((role: string, permissions: string[]) => {
return { role, permissions }
}, 'userRole')
userRole.set('admin', ['read', 'write', 'delete'])

Template

The type of the simple variable (when used with just a name)

Template

Types of parameters for the setter function

Template

The type of the stored value

See

https://github.com/tc39/proposal-async-context?tab=readme-ov-file#asynccontextvariable


withRollback()

withRollback: () => GenericExt

Defined in: packages/core/src/methods/transaction.ts:106

Extension to follow rollback context. For atoms it adds prev state restoration when relative rollback() appears. For actions it adds error handling and call rollback() automatically.

Returns

GenericExt


wrap()

wrap: {<Params, Payload>(target, frame?): (…params) => Payload; <T>(target, frame?): Promise<Awaited<T>>; }

Defined in: packages/core/src/methods/wrap.ts:47

Preserves Reatom’s reactive context across async boundaries or function calls.

This is a CRITICAL function in Reatom that ensures proper context tracking across asynchronous operations like Promises, setTimeout, event handlers, and more. Without proper wrapping, atoms would lose their context after async operations, leading to “Missed context” errors when attempting to update state.

Wrap handles two scenarios:

  1. Function wrapping: Returns a new function that preserves context when called
  2. Promise wrapping: Returns a new promise that preserves context through its chain

Call Signature

<Params, Payload>(target, frame?): (…params) => Payload

Type Parameters
Params

Params extends any[]

Payload

Payload

Parameters
target

(…params) => Payload

frame?

Frame<any, any[], any>

Returns

(…params): Payload

Parameters
params

Params

Returns

Payload

Call Signature

<T>(target, frame?): Promise<Awaited<T>>

Type Parameters
T

T

Parameters
target

T

frame?

Frame<any, any[], any>

Returns

Promise<Awaited<T>>

Example

// Wrapping a function (e.g., an event handler)
button.addEventListener(
'click',
wrap(() => {
counter((prev) => prev + 1) // Works, context preserved
}),
)
// Wrapping async operations
action(async () => {
const response = await wrap(fetch('/api/data'))
const data = await wrap(response.json())
results(data) // Works, context preserved
})

Template

The parameter types when wrapping a function

Template

The return type when wrapping a function

Template

The promise type when wrapping a promise

Param

The function or promise to wrap with context preservation

Param

The frame to use (defaults to the current top frame)

Returns

A wrapped function or promise that preserves reactive context

See

https://github.com/tc39/proposal-async-context?tab=readme-ov-file#asynccontextsnapshotwrap

Functions

connectLogger()

connectLogger(): void

Defined in: packages/core/src/methods/connectLogger.ts:104

Sets up and connects a logger to the Reatom system for debugging and tracing.

This function enhances all non-private atoms and actions with logging capabilities. When an atom’s value changes or an action is called, it logs the event with relevant information to the console including:

  • Previous and current state for atoms
  • Parameters and return values for actions
  • Complete dependency stack traces
  • Error information when exceptions occur

The logger adapts to the environment, using different formatting for browser and Node.js. Private atoms (those with names starting with '' or containing ’.’) are not logged.

Returns

void

Example

// Connect the logger at application startup
import { connectLogger } from '@reatom/core'
connectLogger()

deatomize()

deatomize<Value>(value): Deatomize<Value>

Defined in: packages/core/src/methods/deatomize.ts:76

Recursively unwraps atoms in a value to get their current states

This function deeply traverses a value, including nested objects, arrays, maps, and sets, replacing atoms with their current state values. It’s useful for serialization, debugging, or creating snapshots of state that don’t contain reactive references.

Type Parameters

Value

Value

The type of value to parse

Parameters

value

Value

The value containing atoms to unwrap

Returns

Deatomize<Value>

A new value with all atoms replaced by their current states

Example

const user = {
id: 42,
name: atom('John', 'userName'),
stats: {
score: atom(100, 'userScore'),
badges: atom(['gold', 'silver'], 'userBadges'),
},
}
// Results in: { id: 42, name: 'John', stats: { score: 100, badges: ['gold', 'silver'] }}
const plainUser = deatomize(user)

effect()

effect<T>(cb, name?): Computed<T> & AbortExt & DynamicSubscriptionExt & object

Defined in: packages/core/src/methods/effect.ts:56

Creates a reactive side effect that automatically tracks dependencies and cleans itself up.

effect is similar to computed but designed for running side effects. It automatically subscribes to any atoms read within the callback (cb). When the effect’s reactive context is aborted (e.g., component unmount in reatomFactoryComponent, cancellation in withAbort / withAsyncData), the effect’s execution is stopped, and any ongoing async operations within it (like await wrap(sleep(...))) are cancelled.

Type Parameters

T

T

Parameters

cb

() => T

The function to run as a side effect. It can be async. Any atoms read inside cb will become dependencies.

name?

string

Optional name for debugging purposes. Auto-generated if not provided.

Returns

Computed<T> & AbortExt & DynamicSubscriptionExt & object

The new computed atom with unsubscribe method to manually clean up the effect. Calling this function is usually not necessary when effect is used within managed contexts like reatomFactoryComponent or withConnectHook, as cleanup happens automatically.

Example

import { atom, effect, wrap, sleep, isAbort } from '@reatom/core'
const isActive = atom(true, 'isActive')
const data = atom(0, 'data')
// This effect polls data every 5 seconds while isActive is true
const polling = effect(async () => {
if (!isActive()) return // Depends on isActive
console.log('Polling started...')
while (true) {
const fetchedData = await wrap(fetch('/api/poll'))
const jsonData = await wrap(fetchedData.json())
data(jsonData.value)
await wrap(sleep(5000)) // Abortable sleep == debounce
}
}, 'pollingEffect')
// To manually stop:
// polling.unsubscribe()

framePromise()

framePromise(queue): Promise<unknown>

Defined in: packages/core/src/methods/framePromise.ts:79

Request the result of the current atom or action function as a promise.

Returns a promise that resolves to the current execution frame’s state (action payload or atom state). Use it to catch errors from subsequent operations in a cleaner way than traditional try-catch. Use finally to clean up resources and so on. This method respects wrap and abortVar policies.

Inspired by TC39 explicit resource management proposal, but simpler and coupled to Reatom’s async stack for an ergonomic usage.

Parameters

queue

QueueKind = 'effect'

Queue type to schedule in (default: “effect”)

Returns

Promise<unknown>

Promise that resolves with the current frame’s state

Examples

export const processPayment = action(async (orderId: string) => {
framePromise().catch((error) => showErrorNotification(error))
let order = await wrap(fetchOrder(orderId))
await wrap(validateInventory(order))
await wrap(chargeCustomer(order))
await wrap(updateOrderStatus(order, 'completed'))
return order
})
// Classic approach - boilerplate with try-catch
export const doSome = action(async () => {
try {
await wrap(fetchUser())
await wrap(updateProfile())
await wrap(syncData())
} catch (error) {
toast(error)
}
})
// native using - no try-catch and no "finally" logic
// only resource management with extra variables
// you can adapt `toast`, but without the payload / error data
export const doSome = action(async () => {
using _ = toast
await wrap(fetchUser())
await wrap(updateProfile())
await wrap(syncData())
})
// With our framePromise() - clean and declarative
export const doSome = action(async () => {
framePromise().catch((error) => toast(error))
await wrap(fetchUser())
await wrap(updateProfile())
await wrap(syncData())
})
// Native using works only within the current function scope=*
export const processOrder = action(async (orderId: string) => {
withErrorLogging() // Impossible with native using
await wrap(fetchOrder(orderId))
})
// But framePromise works with the current action/atom frame!
// Helper functions can use parent's framePromise - powerful composition!
let withErrorLogging = () => {
framePromise().catch((error) => logger.error(error))
}
export const processOrder = action(async (orderId: string) => {
withErrorLogging() // Helper uses the SAME action frame!
await wrap(fetchOrder(orderId))
})

See

https://github.com/tc39/proposal-explicit-resource-management


getCalls()

getCalls<Params, Payload>(target): object[]

Defined in: packages/core/src/methods/ifChanged.ts:97

Retrieves new action calls that occurred in the current batch.

This utility function tracks action invocations and returns an array of new calls that have been made during the current batch. It’s particularly useful for monitoring action activity within computed atoms or effects without triggering side effects during the action execution itself.

In a computed atom, the function compares the current action state with the previous frame’s state to determine which calls are new. If this is the first time the action is being tracked, all current calls are considered new. Otherwise, only calls that weren’t present in the previous frame are returned. If the computed triggered by some other dependent atom change, the function may return an empty array. The past calls are not stored!

Type Parameters

Params

Params extends any[]

Array type representing the action’s parameter types

Payload

Payload

Type of the action’s return value/payload

Parameters

target

Action<Params, Payload>

The action to monitor for new calls

Returns

object[]

Array of new action calls, each containing the action’s payload (return value) and the parameters it was called with

Example

// Monitor API calls in an effect
const apiCall = action((endpoint: string) => fetch(endpoint), 'apiCall')
effect(() => {
const newCalls = getCalls(apiCall)
newCalls.forEach(({ payload, params }) => {
console.log(`API called: ${params[0]}, Response:`, payload)
})
}, 'apiMonitor')

Throws

If target is a reactive atom instead of an action


getSerial()

getSerial(frame): string

Defined in: packages/core/src/methods/getStackTrace.ts:10

Parameters

frame

Frame<any, any[], any> = ...

Returns

string


ifCalled()

ifCalled<Params, Payload>(target, cb): void

Defined in: packages/core/src/methods/ifChanged.ts:140

Type Parameters

Params

Params extends any[]

Payload

Payload

Parameters

target

Action<Params, Payload>

cb

(payload, params) => void

Returns

void

Deprecated

Use getCalls instead


ifChanged()

ifChanged<T>(target, cb): void

Defined in: packages/core/src/methods/ifChanged.ts:40

Executes a callback when an atom’s state changes

This utility evaluates if an atom’s state has changed during the current frame execution and calls the provided callback with the new state (and optionally the previous state if available).

Type Parameters

T

T extends AtomLike<any, any[], any>

Type extending AtomLike

Parameters

target

T

The atom to monitor for changes

cb

(newState, oldState?) => void

Callback to execute when the atom changes

Returns

void

Example

// Log when the user's name changes
ifChanged(userName, (newName, oldName) => {
console.log(`Name changed from ${oldName} to ${newName}`)
})

Throws

If target is not a reactive atom


isCausedBy()

isCausedBy(target, frame?, visited?): boolean

Defined in: packages/core/src/methods/isCausedBy.ts:25

Determines if an atom is part of the causal chain leading to the current computation

This recursive function checks if the given atom has caused the current computation by traversing the computation tree. It’s useful for determining dependencies and understanding the flow of state changes through your application.

Parameters

target

AtomLike

The atom to check if it’s part of the causal chain

frame?

Frame<any, any[], any> = ...

The frame to check (defaults to the current top frame). Default is top()

visited?

Set<Frame<any, any[], any>> = ...

Returns

boolean

True if the target atom is part of the causal chain, false otherwise

Example

// Check if user atom changes caused the current computation
if (isCausedBy(userAtom)) {
console.log('This computation was triggered by user state change')
}

isChanged()

isChanged(target): boolean

Defined in: packages/core/src/methods/ifChanged.ts:7

Parameters

target

AtomLike

Returns

boolean


isSkip()

isSkip(target): boolean

Defined in: packages/core/src/methods/getStackTrace.ts:4

Parameters

target

AtomLike

Returns

boolean


memo()

memo<State>(cb, equal, key?): State

Defined in: packages/core/src/methods/memo.ts:112

Memoize additional computation inside a different calls of an atom (computed or an effect) or an action.

It’s useful when you want to avoid recomputing of the whole computed function, especially if the computation is expensive. You could create an external atom by yourself, but it is not handy sometimes.

The memo function takes a callback function cb that returns the value to be memoized, an optional equal function that compares the new and old values to determine if the memoized value should be updated, and an optional key to uniquely identify the memoized value.

Important note: The created internal atom only uses the first passed callback function. This means it’s unsafe to rely on data from the closure that changes on every recall, as subsequent calls will not update the callback used by the internal atom.

Note for rare cases: A created underhood atom is memorized for each memo by the passed function sources from “toString()” method, so every computed callback in different memos of the same atom should contain different code. However, you can provide a custom key parameter to uniquely identify different memo calls instead of relying on toString().

When a custom key is provided, the toString() duplication check is bypassed, allowing you to use the same callback function multiple times within the same atom by providing different keys for each usage.

Type Parameters

State

State

Parameters

cb

A function that returns the value to be selected and memoized.

() => State | (state?) => State

equal

(newState, oldState) => boolean

key?

string

An optional unique identifier for the memoized value. Defaults to cb.toString(). Used to distinguish between different memo calls within the same computed function. Providing a custom key is recommended when using similar callback functions to avoid conflicts.

Returns

State

The memoized value.

Examples

// This is very useful to memoize not just the end string,
// but, for example, a template computation inside `reatomComponent` or so on.
export const listSum = computed(() => {
// Simple call of `list().length` will cause extra recomputations for elements sorting or its internal changes.
// correct optimal way, the component will rerender only on `length` change
const length = memo(() => list().length)
// you could call different `memo` many times in one computed
const sum = memo(() => list().reduce((acc, el) => acc + el().value, 0))
return `The sum of ${length} elements is: ${sum}`
}, 'listSum')
// An example of using the equality function as part of the logic
const scroll = atom(0, 'scroll')
const throttledScroll = computed(() => {
const { state } = memo(
() => ({ state: scroll(), time: Date.now() }),
// Only update if 50ms have passed since the last update
(next, prev) => prev.time + 50 < Date.now(),
)
return state
}, 'throttledScroll')
// Using memo in actions for expensive computations
const processData = action((data: string[]) => {
// You can even create a service, but not one that is tied only to this action.
const myService = memo(() => new Service())
myService.send(data)
}, 'processData')

memoKey()

memoKey<T>(key, create): T

Defined in: packages/core/src/methods/memo.ts:19

Internal utility for keyed memoization within an atom’s execution context.

Caches values by key within the current atom frame, creating the value on first access and returning the cached value on subsequent calls. This enables persistent memoization across multiple invocations of the same atom.

The cache is scoped per-atom and persists across all calls to that atom within the same context, making it suitable for creating internal computed atoms or other resources that should be created once and reused.

Type Parameters

T

T

The type of value being cached

Parameters

key

string

Unique identifier for the cached value within the atom

create

() => T

Factory function to create the value if not already cached

Returns

T

The cached value, either newly created or retrieved from cache


peek()

peek<Params, Result>(cb, …params): Result

Defined in: packages/core/src/methods/peek.ts:38

Executes a callback in the current context without reactive bindings (dependencies tracking)

Type Parameters

Params

Params extends any[]

Result

Result

Parameters

cb

(…params) => Result

params

Params

Returns

Result

Examples

// reset paging on search changes
effect(() => {
const searchState = search()
// get page state without subscribing to it!
if (peek(page) > 1) peek(0)
})
const query = atom('', 'query')
const someResource = computed(
async () => api.getSome(query()),
'someResource',
).extend(withAsyncData())
const tip = computed(() => {
if (!someResource.ready()) {
return 'Searching...'
}
const list = someResource.data()
if (list.length === 0) {
// no need to subscribe to the query changes!
return peek(query) ? 'Nothing found' : 'Try to search something'
}
return `Found ${list.length} elements`
})

reatomTransaction()

reatomTransaction(): TransactionVariable

Defined in: packages/core/src/methods/transaction.ts:37

Creates a transaction variable with rollback capabilities. This variable stores a list of rollback functions that can be executed to revert state changes made within a transaction.

Returns

TransactionVariable

A transaction variable with withRollback middleware and a rollback action.


reset()

reset<T>(target): void

Defined in: packages/core/src/methods/retry.ts:16

Removes all computed atom dependencies. Useful for resources / effects invalidation.

Note that this method not recall and recompute the atom, it only throws it’s deps. Use retryComputed to reevaluate the computed.

Type Parameters

T

T extends AtomLike<any, any[], any>

Parameters

target

T

The reactive atom whose dependencies should be reset.

Returns

void

Throws

If the target is an action.


schedule()

schedule<T>(fn, queue): Promise<T>

Defined in: packages/core/src/methods/schedule.ts:15

Schedule a callback to execute after all current computations complete.

The callback is added to the specified queue (“effect” by default) and processes alongside subscription callbacks and other side effects. This method respects wrap and abortVar policies.

Type Parameters

T

T

Parameters

fn

() => T

Callback function to execute

queue

QueueKind = 'effect'

Queue type to schedule in (default: “effect”)

Returns

Promise<T>

Promise that resolves with the callback’s return value


take()

Call Signature

take<Return>(target, name?): Promise<Awaited<Return>>

Defined in: packages/core/src/methods/take.ts:42

Awaits the next update of an atom or call of an action.

This function returns a Promise that resolves when the specified atom’s state changes or when the specified action is called. This is valuable for orchestrating workflows that depend on future state changes or action calls.

Note: Must be used with wrap() when used in an async context to preserve reactive context.

Type Parameters
Return

Return

Parameters
target

The atom or action to wait for

AtomLike<any, any, Return> | () => Return

name?

string

Optional name for debugging purposes

Returns

Promise<Awaited<Return>>

A promise that resolves with the next value of the atom or action result

Example
// Wait for form validation before proceeding
const submitWhenValid = action(async () => {
while (true) {
const currentData = formData()
const error = validate(currentData)
if (!error) break // Exit loop if valid
formData({ ...currentData, error }) // Show error
// Wait for the next change in formData - need wrap() to preserve context
await wrap(take(formData))
}
// Now formData is valid, proceed with submission...
})

Call Signature

take<Return, Result>(target, map, name?): Result | Promise<Result>

Defined in: packages/core/src/methods/take.ts:58

Awaits the next update of the target AtomLike and maps the result. If the map function executes synchronously without throwing, its result is returned directly. Otherwise, a promise is returned.

Type Parameters
Return

Return

The type of the awaited value from the target.

Result

Result

The type of the mapped result.

Parameters
target

The AtomLike to await.

AtomLike<any, any, Return> | () => Return

map

(value) => Result

A function to map the awaited value.

name?

string

Optional name for debugging.

Returns

Result | Promise<Result>

The mapped result or a promise that resolves with the mapped result.


withObservable()

withObservable<Target>(producer, init?): Ext<Target>

Defined in: packages/core/src/methods/reatomObservable.ts:71

Extends an existing atom to synchronize with an observable-like data source.

This extension bridges external observable sources (like RxJS observables, event emitters, or custom observable implementations) with Reatom’s reactive system. The extended atom will automatically subscribe to the observable when it gains subscribers and unsubscribe when it loses all subscribers.

Type Parameters

Target

Target extends Atom<any, [any]>

The type of the atom being extended

Parameters

producer

Producer<AtomState<Target>>

Either a function that accepts a setter callback and returns an unsubscribe function, or an object with a subscribe method (like RxJS observables)

init?

() => AtomState<Target>

Optional initialization function that returns the initial value. This will be called when the atom is first connected

Returns

Ext<Target>

An extension function that adds observable synchronization to an atom

Examples

// Extending an existing atom with RxJS Observable
import { interval } from 'rxjs'
const counterAtom = atom(0)
const timerAtom = counterAtom.extend(withObservable(interval(1000)))
// With custom observable function
const stateAtom = atom({ timestamp: 0 })
const liveAtom = stateAtom.extend(
withObservable((setter) => {
const id = setInterval(() => setter({ timestamp: Date.now() }), 1000)
return () => clearInterval(id)
}),
)
// With MobX observable, providing initial value
import { autorun, observable } from 'mobx'
const mobxStore = observable({ count: 0 })
const syncedAtom = atom(0).extend(
withObservable((setter) => autorun(() => setter(mobxStore.count))),
)
// With DOM events
const clickCountAtom = atom(0)
const trackedAtom = clickCountAtom.extend(
withObservable((setter) => {
let count = 0
const handler = () => setter(++count)
document.addEventListener('click', handler)
return () => document.removeEventListener('click', handler)
}),
)