In the previous part of this tutorial I’ve discussed how to update application state using actions.
We’ve implemented a simple function that used state’s get
and set
methods to change the count variable.
function changeCounter({props, state}){
state.set("count", state.get("count") + props.param);
}
But doing this repeatedly for each state variable is incredibly redundant and I’ve been saying that Cerebral helps us write cleaner and more DRY code.
Let’s say we add another variable to the state that tracks the previous counter value. Do we need to write another action to update it? Nope. There’s a very clean solution for this.
Tags and operators
Since alot of operations on state are common, i.e. update, delete, splice, check condition, etc, Cerebral provides a set of operators to simplify your code.
Let’s see how we can use them.
We’ll add a state variable called ‘prevCount’ and will copy the ‘count’ to it before each operation.
Here’s how it’s done (showing only the changes):
import {set} from 'cerebral/operators'
import {state} from 'cerebral/tags'
...
state: {
prevCount: 0,
count: 0
},
signals: {
changeCounter:
[
set(state`prevCount`, state`count`),
changeCounter,
logAction
]
}
Let’s break down what we see here:
No new functions were written
We import set operator and state tag
We add set to our signal chain and use the state tag to a) fetch current count b) set it to prevCount
Isn’t that nice and clean?
(full code here)
Anyone who’s reading this file will have an immidiate understanding of what’s going on, because the code reads like English:
When signal changeCounter is fired, do the following: set state prevCount to value of state count, then change counter and call the logAction.
This is what makes action chains with operators great.
And this is just scratching the surface.
Here are some examples of stuff you can do using operators and tags:
Update lists
import {merge, push, pop} from 'cerebral/operators'
import {state, props} from 'cerebral/tags'
export default [
merge(state`some.object`, props`newObj`),
push(state`some.list`, props`newItem`),
pop(state`some.otherList`)
]
Debounce queries
import {set, debounce} from 'cerebral/operators'
import {state, props} from 'cerebral/tags'
import makeQueryRequest from '../chains/makeQueryRequest'
export default [
set(state`query`, props`query`),
debounce(500), {
continue: makeQueryRequest,
discard: []
}
]
Perform conditional execution
import {when, equals} from 'cerebral/operators'
import {state, props} from 'cerebral/tags'
export default [
when(state`app.isAwesome`), {
true: [],
false: []
},
equals(state`user.role`), {
admin: [],
user: [],
otherwise: []
}
]
In it’s guts, an operator is actually an ‘action factory’, meaning, it’s a function returning an action. So you can easily write your own operators to clearly express your intentions and make your code clean.
For a full list of built-in operators, see: http://cerebraljs.com/docs/api/operators.html