Factories are functions that create actions for you. They help you manipulate state and control execution flow with a declarative API.
Cerebral includes a set of factories for common state operations, all imported from ‘cerebral/factories’:
import { set, push, toggle } from 'cerebral/factories'
Concatenate values to an array:
concat(state`list`, ['foo', 'bar'])
Increment a number by a specific value (default is 1):
// Basic increment by 1
increment(state`counter`)
// Increment by specific value
increment(state`counter`, 5)
// Decrement using negative values
increment(state`counter`, -1)
// Use values from state or props
increment(state`counter`, state`incrementBy`)
increment(state`counter`, props`amount`)
Merge objects into existing values:
// Simple merge
merge(state`user`, { name: 'John', age: 30 })
// Merge with props
merge(state`user`, props`userData`)
// Merge with dynamic keys
merge(state`clients.$draft`, {
name: props`name`,
email: props`email`
})
Remove and return last element from an array:
pop(state`items`)
Add items to the end of an array:
push(state`items`, 'new item')
push(state`items`, props`newItem`)
Set a value in state or props:
// Basic usage
set(state`user.name`, 'John')
set(props`redirect`, true)
// Transform value before setting
set(state`count`, props`count`, (value) => value * 2)
Remove and return the first element from an array:
shift(state`items`)
Modify an array by removing or replacing elements:
// Remove 2 elements starting at index 0
splice(state`items`, 0, 2)
// Remove 1 element at index 2 and insert new elements
splice(state`items`, 2, 1, 'new item', props`item2`)
Toggle a boolean value:
toggle(state`menu.isOpen`)
Remove a property from an object:
unset(state`user.temporaryData`)
unset(state`items.${props`itemKey`}`)
Add elements to the beginning of an array:
unshift(state`items`, 'new first item')
These factories help control the execution flow of your sequences.
Delay execution of a path until a specified time has passed without another call:
import { debounce } from 'cerebral/factories'
// Basic usage
;[
debounce(500), // Wait 500ms without new calls
{
continue: [actions.search], // Run when debounce completes
discard: [] // Must be present - run when debounce is abandoned
}
]
// Shared debounce across multiple sequences
const sharedDebounce = debounce.shared()
export const notifyUser = [
set(state`notification`, props`message`),
sharedDebounce(2000),
{
continue: [unset(state`notification`)],
discard: []
}
]
The discard
path must always be present when using debounce, even if you don’t need to run any actions when debounce is abandoned.
Branch execution based on a value comparison:
equals(state`user.role`),
{
admin: [actions.loadAdminPage],
user: [actions.loadUserPage],
otherwise: [actions.redirectToLogin]
}
Pause execution for a specified time:
// Simple waiting
;[wait(500), actions.afterWaiting]
// Within parallel execution
parallel([
[
wait(500),
{
continue: [actions.afterWaiting]
}
],
actions.runInParallel
])
Conditionally choose a path based on a value or predicate:
// With direct value
when(state`user.isLoggedIn`),
{
true: [actions.redirectToDashboard],
false: [actions.showLoginForm]
}
// With custom predicate
when(state`user.role`, (role) => role === 'admin'),
{
true: [actions.showAdminTools],
false: []
}
// With multiple arguments
when(
state`inputValue`,
state`minLength`,
(value, minLength) => value.length >= minLength
),
{
true: [set(state`isValid`, true)],
false: [set(state`isValid`, false)]
}
These factories help compose sequences and run actions in parallel:
import { sequence, parallel } from 'cerebral/factories'
// Create a named sequence
export const mySequence = sequence('My Sequence', [
actions.doSomething,
set(state`foo`, 'bar')
])
// Run actions in parallel
export const loadData = [
parallel('Load Data', [
actions.loadUsers,
actions.loadPosts,
actions.loadSettings
]),
set(state`isLoaded`, true)
]
For more detailed usage examples and advanced patterns, see the factories guide.