import React, { Component } from 'react'; import { connect as dvaConnect } from 'dva'; import startsWith from 'lodash/fp/startsWith'; import flow from 'lodash/fp/flow'; import mapKeys from 'lodash/fp/mapKeys'; import pickBy from 'lodash/fp/pickBy'; import { getApp } from '../../data/app'; const connect = (modelCreator, { app, mapStateToProps, mapDispatchToProps, mergeProps, options }) => (Comp) => { const { dispatchVar, namespaceVar } = (options || {}); class StatefulComponent extends Component { constructor(props, context) { super(props, context); const { name, model } = modelCreator(); this.name = name; this.model = model; const mapState = (state) => { const pps = mapStateToProps ? mapStateToProps(state) : {}; pps[name] = state[model.namespace]; pps[namespaceVar || 'namespace'] = model.namespace; if (state.loading) { pps.loading = state.loading; pps.loading.model = pps.loading.models[model.namespace]; pps.loading.effect = flow( pickBy((v, k) => startsWith(`${model.namespace}/`, k)), mapKeys(k => k.slice(model.namespace.length + 1)), )(pps.loading.effects); } return pps; }; const mapDispatch = (dispatch) => { const extras = mapDispatchToProps ? mapDispatchToProps(dispatch) : {}; return { dispatch, ...extras, [dispatchVar || 'dispatchLocal'](action) { const { type, payload } = action; return dispatch({ type: `${model.namespace}/${type}`, payload }); }, }; }; this.Output = dvaConnect(mapState, mapDispatch, mergeProps, options)(Comp); } componentWillMount() { (app || this.props.app || getApp()).model(this.model); } componentWillUnmount() { (app || this.props.app || getApp()).unmodel(this.model.namespace); } render() { const { children, ...rest } = this.props; return ( <this.Output {...rest}> { children } </this.Output> ); } } return StatefulComponent; }; export default connect;