UNPKG

midux

Version:

A simple adapter for mithril and redux

162 lines (141 loc) 3.53 kB
/* eslint-disable */ import stream from "mithril/stream"; import { createStore as createReduxStore, applyMiddleware, combineReducers, bindActionCreators } from "redux"; /** * Mithril module reference. This is to ensure that the same redraw loop and internal module handling is in fact exact * to the application itself. * @type {Function} */ let m = null; /** * Initialize the library to utilize the exact reference to mithril as the base application * @param {Function} mithrilModule reference to the application's mithril instance */ export const init = mithrilModule => { m = mithrilModule; }; /** * Provider function that returns configured store * * @returns {Function} */ export const store = stream(null); /** * Generates a new action creator for dispatching requests. * * @param type * @param argNames * @returns {Function} */ export const makeActionCreator = (type, ...argNames) => (...args) => { const action = { type }; argNames.forEach((arg, index) => { action[argNames[index]] = args[index]; }); return action; }; /** * Generates a new reducer for handling action requests * * @param initialState * @param handlers * @returns {Function} */ export const createReducer = (initialState, handlers) => ( state = initialState, action ) => { if (handlers.hasOwnProperty(action.type)) { return handlers[action.type](state, action); } else { return state; } }; /** * Default prop to store mapping * * @param state * @param props */ export const defaultMapStateToProps = (state, props) => state; /** * Connect container component to redux store * * @param store */ export const connect = ( mapStateToProps, mapActionCreators = {} ) => component => ({ oninit(vnode) { this.store = store(); this.componentState = stream({}); this.unsubscribe = null; this.actions = bindActionCreators(mapActionCreators, this.store.dispatch); this.isSubscribed = () => typeof this.unsubscribe === "function"; this.trySubscribe = () => { if (!this.isSubscribed()) { this.unsubscribe = this.store.subscribe( this.handleUpdate.bind(this, vnode) ); this.handleUpdate(vnode); } }; this.tryUnsubscribe = () => { if (this.isSubscribed()) { this.unsubscribe(); this.unsubscribe = null; } }; this.handleUpdate = vnode => { if (!this.isSubscribed()) return true; const ownProps = vnode.attrs || {}; const storeState = mapStateToProps(this.store.getState(), ownProps); this.componentState(storeState); setTimeout(m.redraw); }; this.trySubscribe(); }, onbeforeremove(vnode) { if (typeof component.onbeforeremove === "function") return component.onbeforeremove(vnode); }, onremove(vnode) { this.actions = null; this.store = null; this.componentState = null; this.tryUnsubscribe(); }, view(vnode) { const actions = this.actions; const storeProps = this.componentState(); return m( component, { actions, ...storeProps, ...vnode.attrs }, vnode.children ); } }); /** * Configure store to use reducers/middleware * * @param reducers * @param initialState * @param middleware * @returns {Store<S>} */ export const createStore = (reducers, initialState = {}, middleware = []) => { store( createReduxStore( combineReducers(reducers), initialState, applyMiddleware(...middleware) ) ); return store(); };