In Cerebral, factories are functions that create actions. This pattern gives you power to create reusable, configurable actions:
function createAction(config) {
return function action(context) {
// Use config and context here
}
}
Factories help you:
Here’s a simple factory that creates a message:
function createMessager(name) {
function message({ store }) {
store.set('message', `Hello ${name}!`)
}
return message
}
// Use it in a sequence
export const sayHello = [
createMessager('Bob')
// Result: sets state.message to "Hello Bob!"
]
One common use case is creating factories for API requests:
function httpGetFactory(url) {
function httpGetAction({ http, props }) {
return http.get(url).then((response) => ({ response: response.data }))
}
return httpGetAction
}
// Usage
export const getUsers = [
httpGetFactory('/api/users'),
set(state`users`, props`response`)
]
Let’s improve our factory to handle dynamic values using Cerebral’s tag system:
import { string, props } from 'cerebral'
function httpGetFactory(url) {
function httpGetAction({ http, get }) {
// Resolve the URL if it's a tag
const resolvedUrl = get(url)
return http
.get(resolvedUrl)
.then((response) => ({ response: response.data }))
}
return httpGetAction
}
// Usage with dynamic URL
export const getUser = [
httpGetFactory(string`/api/users/${props`userId`}`),
set(state`currentUser`, props`response`)
]
Factories can support branching execution paths:
function httpGetFactory(url) {
function httpGetAction({ http, get, path }) {
const resolvedUrl = get(url)
// Check if this action is used with paths
if (path) {
return http
.get(resolvedUrl)
.then((response) => path.success({ response: response.data }))
.catch((error) => path.error({ error: error.response }))
} else {
// Regular promise return when not using paths
return http
.get(resolvedUrl)
.then((response) => ({ response: response.data }))
}
}
return httpGetAction
}
// Usage with paths
export const getUsers = [
httpGetFactory('/api/users'),
{
success: set(state`users`, props`response`),
error: set(state`error`, props`error`)
}
]
You can enhance factories to choose paths based on status codes:
function httpGetFactory(url) {
function httpGetAction({ http, get, path }) {
const resolvedUrl = get(url)
if (path) {
return http
.get(resolvedUrl)
.then((response) => {
// Choose path based on status code or use default success
return path[response.status]
? path[response.status]({ response: response.data })
: path.success({ response: response.data })
})
.catch((error) => {
return path[error.response?.status]
? path[error.response?.status]({ error: error.response })
: path.error({ error: error.response })
})
} else {
// Regular promise return
return http
.get(resolvedUrl)
.then((response) => ({ response: response.data }))
}
}
return httpGetAction
}
// Usage with status paths
export const getUsers = [
httpGetFactory('/api/users'),
{
success: set(state`users`, props`response`),
404: set(state`error`, 'Users not found'),
error: set(state`error`, props`error.message`)
}
]
Sometimes you need to resolve not just the value of a tag, but its path:
function setFactory(target, value) {
function setAction({ store, resolve }) {
// Check if target is a state tag
if (resolve.isTag(target, 'state')) {
// Get the path from the tag (e.g., "users.list")
const path = resolve.path(target)
// Get the value to set, which might also be a tag
const resolvedValue = resolve.value(value)
// Update state at the resolved path
store.set(path, resolvedValue)
} else {
throw new Error('Target must be a state tag')
}
}
return setAction
}
// Usage
export const updateUser = [
setFactory(state`users.${props`userId`}`, props`userData`)
]
Here are some useful custom factories you can create:
// Notification factory
function notifyFactory(message) {
return function notify({ store, get }) {
store.set('notifications.message', get(message))
store.set('notifications.visible', true)
}
}
// Timeout factory
function delayFactory(ms) {
return function delay() {
return new Promise((resolve) => setTimeout(resolve, ms))
}
}
// Usage
export const showNotification = [
notifyFactory('Operation successful!'),
delayFactory(3000),
set(state`notifications.visible`, false)
]
Custom factories are a powerful way to create reusable logic in your Cerebral application while keeping your sequences clean and declarative.