rereduce - Reducer library for Redux
Rereduce
Simple reducer library for Redux. It's like Reselect but for reducers.
Reducers can depend on each others.
It permits to replace the imperative waitFor
of original Flux implementation by a purely functional approach.
/!\ Work in progress: Current implementation does not play well (yet) with server-side rendering or time-travel.
API
createReducer( [reducerDependencies], reducerFunction)
[reducerDependencies]
is an optional object that looks like {key1: reducer1, key2: reducer2}
If dependencies are provided, reducerFunction
will be called with a 3rd argument with the state of the dependency reducers.
Note that the API is a first draft and may change in the future. Don't hesitate to discuss what the API should look like here: https://github.com/slorber/rereduce/issues/1
Simple example
import { createReducer } from 'rereduce'
// Create a simple reducer without dependencies
const firstReducer = createReducer(function(state = 0, action) {
switch (action.type) {
case 'increment': return state + 1
case 'decrement': return state - 1
default: return state
}
})
// Create another reducer that depends on first reducer
const secondReducer = createReducer({ firstReducer }, // declare dependency to firstReducer
function(state = 0,action,{firstReducer}) {
return firstReducer + 1
}
)
// Everytime secondReducer is called, firstReducer will also be called
// firstReducer is memoized so it is not inefficient to call it multiple times</pre> </div>
How it worksWhat it does in reality:
- It memoizes reducers so that they can be reused efficiently
- It permits to create reducers depending on other reducers </ul>
The core logic is simple, it's just 10 lines of code :) the rest is FP utility code.
export function createReducer() {
const { reducerDependencies,reducer,reducerMemoizer } = parseArgs(arguments)
// This variable tracks the state of the reducer dependencies
// These states are all initialized to undefined
let reducerStates = mapValues(reducerDependencies,() => undefined)
const liftedReducer = function(state, action) {
// Compute reducer dependency states
reducerStates = mapValues(reducerStates,(state,key) => {
return reducerDependencieskey
})
// Call reducer function provided by user and injects reducer dependency states
return reducer(state,action,reducerStates)
}
// Memoize the reducer so that it can be used efficiently as a dependency to other reducers
return reducerMemoizer(liftedReducer)
}</pre> </div>
Unit test
import { createReducer } from 'rereduce'
const a = createReducer((state = 0, action) => {
switch (action.type) {
case 'increment': return state + 1
case 'decrement': return state - 1
default: return state
}
})
const b = createReducer((state = 5, action) => {
switch (action.type) {
case 'increment': return state + 10
case 'decrement': return state - 10
default: return state
}
})
const c = createReducer({ a,b }, (state = 0,action,{ a,b }) => {
const sum = a + b
return state + sum
})
const d = createReducer({ c }, (state = 0,action,{ c }) => {
return c + 1
})
const counters = combineReducers({ a, b , c, d })
let state
state = counters(state, { type: 'init' })
assert.equal(state.a, 0)
assert.equal(state.b, 5)
assert.equal(state.c, 5)
assert.equal(state.d, 6)
state = counters(state, { type: 'increment' })
assert.equal(state.a, 1)
assert.equal(state.b, 15)
assert.equal(state.c, 21)
assert.equal(state.d, 22)</pre> </div>
本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!