Intermediate example: custom logic
Play around with this code on Runkit
Situation: I want to define a general type of reducer logic that can be reused on any arbitrary slice of state.
Complication: I want to do this as quickly, painlessly and intuitively as possible.
Question: Do I really have to create sub-reducers with the same underlying logic?
Answer: no! Just provide Redux-Leaves once with your custom reducer logic, and you can automatically use it at any leaf of your state tree.
Demonstration
Set up with your custom reducer logic
import { createStore } from 'redux'
import reduxLeaves from 'redux-leaves'
const initialState = {
counter: 2,
list: ['first', 'second'],
nested: { arbitrarily: { deep: 0 } }
}
// Key your reducer logic by a descriptive verb
const reducersDict = {
double: leafState => leafState * 2,
appendToEach: (leafState, action) => leafState.map(str => str.concat(action.payload)),
countTreeKeys: (leafState, action, treeState) => Object.keys(treeState).length
}
// Provide the dictionary of your reducer logic to reduxLeaves
const [reducer, actions] = reduxLeaves(initialState, reducersDict)
const store = createStore(reducer)
Dispatch actions at any leaf with the corresponding keys
store.dispatch(actions.counter.create.double())
console.log(store.getState().counter) // 4
store.dispatch(actions.list.create.appendToEach(' item')) // ' item' will be the action payload
console.log(store.getState().list) // ['first item', 'second item']
store.dispatch(actions.nested.arbitrarily.deep.create.countTreeKeys())
console.log(store.getState().nested.arbitrarily.deep) // 3
// And to demonstrate reusing logic at an arbitrary leaf:
store.dispatch(actions.nested.arbitrarily.deep.create.double())
console.log(store.getState().nested.arbitrarily.deep) // 6
Default handling of arguments
When you supply reduxLeaves
with custom reducer logic, it provides the corresponding action creators, e.g. actions.list.create.appendToEach
used above.
The default behaviour of these action creators is that, if they receive any arguments, only the first argument is passed to the created action as a payload:
const actionToAppend = actions.list.create.appendToEach('foo', 'bar')
console.log(actionToAppend.payload) // 'foo'
If you would like to customise this behaviour, look at the advanced example.