A set of helper operators to transform actions payload or an atoms state.

included in @reatom/framework


Simple map utility, which allow you to receive previous dependency state by a second optional argument.

import { mapState } from '@reatom/lens'

export const bAtom = atom((ctx) => ctx.spy(aAtom) + 1)
// equal to
export const bAtom = aAtom.pipe(mapState((ctx, state, prevState) => state + 1))


Map payload of each action call. Resulted action is not callable.

import { mapPayload } from '@reatom/lens'

export const changeFullname = changeName.pipe(
  mapPayload((ctx, { firstName, lastName }) => `${firstName} ${lastName}`),

You could pass initial state by first argument to create an atom.

import { action } from '@reatom/core'
import { mapPayload } from '@reatom/lens'

export const onInput = action('onInput')
export const inputAtom = onInput.pipe(
  mapPayload('', (ctx, event) => event.currentTarget.value, 'inputAtom'),


Map fulfilled value of async action call. Resulted action is not callable.

import { mapPayloadAwaited } from '@reatom/lens'

export const newData = fetchData.pipe(mapPayloadAwaited())
// OR pick needed value
export const newData = fetchData.pipe(
  mapPayloadAwaited((ctx, response) => response.data),

You could pass initial state by first argument to create an atom.

import { mapPayloadAwaited } from '@reatom/lens'

export const dataAtom = fetchList.pipe(
  mapPayloadAwaited((ctx, response) => response.data),


Create action witch map input to passed action / atom.

import { atom } from '@reatom/core'
import { mapInput } from '@reatom/lens'

export const inputAtom = atom('', 'inputAtom')
export const changeInput = inputAtom.pipe(
  mapInput((ctx, event) => event.currentTarget.value, 'changeInput'),


Filter updates by comparator function, which should return true, if new state should continue to propagate (“shallow equal” by default).

import { filter } from '@reatom/lens'

export const listMemoAtom = listAtom.pipe(filter())
// equals to
export const listMemoAtom = listAtom.pipe(
  filter((ctx, next, prev) => !isShallowEqual(next, prev)),


Delay updates by timeout.

import { action } from '@reatom/core'
import { debounce, mapPayload } from '@reatom/lens'

export const startAnimation = action()
export const endAnimation = startAnimation.pipe(debounce(250))


Delay updates until other atom update / action call.

This code is taken from this example.

import { mapPayload, sample } from '@reatom/lens'

export const lastRequestTimeAtom = fetchData.pipe(
  mapPayload(0, () => Date.now(), 'fetchStartAtom'),
  mapState((ctx, start) => start && Date.now() - start, 'lastRequestTimeAtom'),


Convert an action to atom with optional init state.

import { mapPayloadAwaited, toAtom } from '@reatom/lens'

export const dataAtom = fetchData.pipe(mapPayloadAwaited(), toAtom([]))


Removes all extra properties, useful for exports cleaning.

import { plain } from '@reatom/lens'

const _fetchData = reatomFetch('...')

// ... some module logic with `_fetchData.retry` etc

// allow external modules only fetch data and not manage it by other ways
export const fetchData = _fetchData.pipe(plain)


Removes all callable signature, useful for exports cleaning.

import { readonly } from '@reatom/lens'

const _countAtom = atom(0)
export const changeCount = action((ctx) => {
  // the module extra logic here

// disallow atom to be mutated outside the module
export const countAtom = _countAtom.pipe(readonly)


Parse tree-like structure by replacing atoms by its values.

// some_form.ts
import { parseAtoms } from '@reatom/lens'

export const submit = action((ctx) => {
  const data = parseAtoms({ titleAtom, commentsAtom })

  return ctx.schedule(() => api.someSubmit(data))


Bind context to stable function.

import { action, createCtx } from '@reatom/core'
import { bind } from '@reatom/lens'

const doSome = action()
const ctx = createCtx()

export handleSome = bind(ctx, doSome)

// 123

bind(ctx, doSome) === bind(ctx, doSome)
// true


Adds reset action to reset the atom state.

For example, clear state after all dependencies and subscribers are gone.

import { atom } from '@reatom/core'
import { withReset } from '@reatom/lens'
import { onDisconnect } from '@reatom/hooks'

export const dataAtom = atom([], 'dataAtom').pipe(withReset())
onDisconnect(dataAtom, dataAtom.reset)