redux-reorder
Version:
Higher-order reducer that tracks order fluctuation within iterable state
49 lines (46 loc) • 1.84 kB
JavaScript
import isEqual from 'lodash/isEqual'
import { isIterable } from 'iterall'
import { INITIALIZE_REORDERS } from './actions'
// @TODO: create a better abstraction / heuristic than `step` and do away with
// need for explicit reorderType...
export default function grokReorders(reducer, { step = 1, reorderType } = {}) {
const initialState = {
iterable: reducer(undefined, {}),
fluctuationMap: []
}
let calls = 0
let fluctuationMap = []
let prevIterableAsArray = Array.from(initialState.iterable)
return (state = initialState, action) => {
const nextIterable = reducer(state.iterable, action)
// @TODO: obviate by 'putting everything on hold' until we get iterable state?
if (!isIterable(nextIterable)) {
throw new TypeError(
`grokReorders expects a reducer that returns iterable state.
Instead the reducer returned a ${typeof nextIterable}.
See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols#iterable`
)
}
const nextIterableAsArray = Array.from(nextIterable)
switch (action.type) {
case INITIALIZE_REORDERS:
calls = 0
return { iterable: nextIterable, fluctuationMap: [] }
case reorderType:
// If enough fluctuation has 'accumulated', represent this fluctuation
// and store the new iterable state.
// @TODO: prove you will never need >= here
if (++calls === step) {
fluctuationMap = nextIterableAsArray.map((x, i) => {
const prevIndex = prevIterableAsArray.findIndex(y => isEqual(y, x))
return prevIndex !== -1 ? prevIndex - i : 0
})
calls = 0
prevIterableAsArray = nextIterableAsArray
}
return { iterable: nextIterable, fluctuationMap }
default:
return state
}
}
}