Operators

You can call operators to create actions for you. These actions will help you change state and control the flow of execution.

Read more about operators in the Cerebral in depth - Operators article.

State operators

The methods for changing state within actions is also available as operators. All state operators support using both state and props tags as values.

All operators are imported as members of the ‘cerebral/operators’ module. For example, this imports state and set:

import {set} from 'cerebral/operators'
import {state} from 'cerebral/tags'

concat

Concatenate a value to an array

concat(state`some.list`, ['foo', 'bar'])

merge

Merge objects into existing value. If no value exists, an empty object will be created. Merge supports using operator tags on key values:

merge(state`clients.$draft`, props`newDraft`, {
  foo: 'bar',
  bar: props`baz`
})

pop

Pop a value off an array (removes last element from array).

pop(state`some.list`)

push

Push value into an array (adds the element at the end of the array).

push(state`some.list`, 'foo')

set

Set a target value in the state or props.

set(state`foo.bar`, true),
set(props`foo`, true)

shift

Shift a value off an array (removes first element in array).

shift(state`some.list`),

splice

Splice an array in place.

splice(state`some.list`, 0, 2)

toggle

Toggle a boolean value.

toggle(state`user.$toolbar`)

unset

Unset key from object.

unset(state`clients.all.${props`key`}`)

unshift

Unshift a value into an array (adds the element at the start of the array).

unshift(state`some.list`, 'foo')

increment

Increment an integer value by another integer value into an array. The default increment is 1, and a negative value effectively does a decrement.

increment(state`some.integer`)
increment(state`some.integer`, -5)
increment(state`some.integer`, state`some.otherInteger`)
increment(state`some.integer`, props`some.otherInteger`)

Flow control operators

These operators help control the execution flow.

equals

This operator chooses a specific path based on the provided value.

import {equals} from 'cerebral/operators'
import {state} from 'cerebral/tags'

export default [
  equals(state`user.role`), {
    admin: [],
    user: [],
    otherwise: [] // When no match
  }
],

debounce

Hold action until the given amount of time in milliseconds has passed. If the signal triggers again within this time frame, the previous signal goes down the “discard” path while the new signal holds for the given time. This is typically used for typeahead functionality. For a debounce that is shared across different signals, you can use debounce.shared() (see example below).

Please note that the discard path has to be present even if it is most often empty because debounce is a flow operator that routes the flow depending on time and action trigger.

import {debounce} 'cerebral/operators'

export default [
  debounce(200), {
    continue: [runThisAction],
    discard: []
  },
]

debounce.shared() is typically used with factories, for example to show notifications where a previous notification should be cancelled by a new one.

import {debounce, set, unset} from 'cerebral/operators'
import {state} from 'cerebral/tags'

const sharedDebounce = debounce.share()
function showNotificationFactory(message, ms) {
  return [
    set(state`notification`, message),
    sharedDebounce(ms), {
      continue: [unset(state`notification`)],
      discard: []
    }
  ]
}

Now when this notification factory is used in different signals, the call to debounceShared will share the same debounce execution state:

import showNotification from './showNotification'

export default [
  // ... user log in, etc
  ...showNotification('User logged in', 5000)
]

wait

Wait for the given time in milliseconds and then continue chain.

import {wait} from 'cerebral/operators'

export default [
  wait(200),
  doSomethingAfterWaiting
]

If you need to wait while executing in parallel, you should use a continue path to isolate the actions to be run:

import {wait} from 'cerebral/operators'
import {parallel} from 'cerebral'

export default
  someAction,
  parallel('my parallel with wait', [
    wait(200), {
      continue: [doSomethingAfterWaiting]
    },
    otherActionInParallel
  ])
]

when

Run signal path depending on a truth value or function evaluation.

import {when} from 'cerebral/operators'

export default [
  when(state`foo.isAwesome`), {
    true: [],
    false: []
  },
  // You can also pass your own function
  when(state`foo.isAwesome`, (value) => value.length === 3 ), {
    true: [],
    false: []
  }
]

When used with a truth function, the when operator supports more then a single “value” argument. The truth function must come last.

import {when} from 'cerebral/operators'
import {props, state} from 'cerebral/tags'

export default [
  when(state`clients.$draft.key`, props`key`,
    (draftKey, updatedKey) => draftKey === updatedKey
  ), {
    true: [
      // Another person edited client, reset form to new value
      set(state`clients.$draft`, props`value`)
    ],
    false: []
  }
]