@girders-elements/core
Version:
Girders Elements is an architectural framework that assists with building data-driven apps with React or React Native.
67 lines (54 loc) • 1.97 kB
JavaScript
import R from 'ramda'
import * as actions from '../action'
import { types as actionTypes } from './actions'
import * as data from '../data'
import { ActionRegistry } from '../registry'
import { findParentEntry } from '../impl/cursor'
import { error } from '../impl/log'
const updateStateAction = '@@girders-elements/_effects.updateState'
export const middleware = R.curry((config, store, next, action) => {
const { kernel, effectsRegistry } = config
const actionMeta = actions.actionMeta(action)
if (actionMeta == null) return next(action)
const key = ActionRegistry.keyFromAction(action)
let effect = effectsRegistry.get(key)
let context = kernel.focusOn(actionMeta.keyPath)
if (effect == null && action.type.startsWith('.')) {
// global action
const keyFn = el => ActionRegistry.keyFor(data.kindOf(el), action.type)
const entry = findParentEntry(effectsRegistry, keyFn, context.query())
if (entry != null) {
const { element, entry: eff } = entry
effect = eff
context = kernel.focusOn(element._keyPath)
}
}
if (effect != null) {
const result = effect(context, action)
if (result && typeof result.then === 'function') {
result
.then(updateFn => {
if (typeof updateFn === 'function') {
context.dispatch({ type: updateStateAction, updateFn })
}
})
.catch(e => {
kernel.dispatch({ type: actionTypes.fail, error: e })
error('Exception while executing an effect: ', e)
})
} else if (typeof result === 'function') {
context.dispatch({ type: updateStateAction, result })
}
} else {
// the effect consumes the action
return next(action)
}
})
export const reducer = R.curry((config, state, action) => {
if (action.type === updateStateAction) {
const { keyPath } = actions.actionMeta(action)
return state.updateIn(keyPath, action.updateFn)
}
return state
})