All atoms and actions by default includes pipe operator for simple extending and composing. You can create your own operators to improve your code and modularize it.
We assume that you already read core docs.
Operator for the pipe function should starts with a verb.
import { Atom, CtxSpy } from ' @reatom/core '
declare function mapState < T , Res > (
mapper : Fn <[ CtxSpy , T , undefined | T ] , Res >,
) : ( anAtom : Atom < T > ) => Atom < Res >
Real mapState
If operator isn’t create a new atom and mutate the passed you should use with
prefix.
import { Atom, AtomState } from ' @reatom/core '
declare function withStateHistory < T extends Atom > (
stateHistoryAtom : Atom < AtomState < T >>
We use here T extends Atom
instead of much simpler <T>(length: string): (anAtom: Atom<T>) Atom<T> & {...}
to save all additional properties witch added by previous operators.
Real historyAtom
import { action, atom, Atom } from ' @reatom/core '
// operator accepts an options by a first argument
// and returns function witch accepts target atom
// to improve debugability compute name of the new atom
const name = ` ${ anAtom . __reatom . name } .delay `
// hide unnecessary meta by `_` prefix in name
const update = action < T > ( ` ${ name } ._update ` )
const updateTimeout = atom ( - 1 , ` ${ name } ._updateTimeout ` )
return atom ( ( ctx , prevState ?: T ) => {
const state = ctx . spy (anAtom)
// more about action spying: https://www.reatom.dev/core#action-api
const updates = ctx . spy (update)
// first call, no need to delay
if (prevState === undefined ) return state
// update from the schedule below
if (updates . length ) return updates . at ( - 1 ) !. payload
// do not forget to schedule all side effects!
clearTimeout (ctx . get (updateTimeout))
const timeout = setTimeout ( () => update (ctx , state) , ms)
updateTimeout (ctx , timeout)
Real debounce
↗