/**
 * 组合ducks，创建redux store
 */ import { Component , createElement } from "react" ; import { createStore as createReduxStore , applyMiddleware , compose } from "redux" ; import createSagaMiddleware , { SagaIterator , SagaMiddleware , Task } from "redux-saga" ; import { connect } from "react-redux" ; import { parallel } from "redux-saga-catch" ; import BaseDuck from "./BaseDuck" ; /** Fire when React Root Component mounted @deprecated */ export const INIT = "@@duck-runtime-init" ; /** Fire when React Root Component unmounted @deprecated */ export const END = "@@duck-runtime-end" ; export interface DuckCmpProps < T = any > { duck : T ; store : any ; dispatch : ( action : any ) => any ; } export interface DuckRuntimeOptions { middlewares ? : any [ ] ; enhancers ? : any [ ] ; } export default class DuckRuntime < TDuck extends BaseDuck = BaseDuck > { duck : TDuck ; private middlewares : any [ ] ; private enhancers : any [ ] ; private sagaMiddleware : SagaMiddleware < any > ; public store : any ; private _tasks : Task [ ] = [ ] ; param { * } duck param middlewares constructor ( duck , options ? ) ; constructor ( duck , ... middlewares ) ; constructor ( duck , ... middlewares ) { this . duck = duck ; let options ; if ( middlewares . length === 1 && typeof middlewares [ 0 ] === 'object' ) { options = middlewares [ 0 ] ; } else { options = { middlewares } ; } this . middlewares = options . middlewares || [ ] ; this . enhancers = options . enhancers || [ ] ; this . _initStore ( ) ; } /**
       * 创建redux store
       */ protected _initStore ( ) { const duck = this . duck ; const sagaMiddleware = ( this . sagaMiddleware = createSagaMiddleware ( ) ) ; const enhancer = compose ( applyMiddleware ( sagaMiddleware , ... this . middlewares ) , ... this . enhancers ) ; this . store = createReduxStore ( < any > duck . reducer , < any > enhancer ) ; this . addSaga ( duck . sagas ) ; } param { Array < Saga | Generator > } sagas addSaga ( sagas ) { const task = this . sagaMiddleware . run ( function * ( ) { yield parallel ( sagas ) ; } ) ; this . _tasks . push ( task ) ; return task ; } /**
     * 停止一切已添加的sagas
     * stop every added sagas.
     */ destroy ( ) { const tasks = this . _tasks ; this . _tasks = [ ] ; tasks . forEach ( task => { task . cancel ( ) ; } ) ; } duckContainer connect ( ) { const duck = this . duck ; return function decorate ( Container ) { return connect ( state => ( { store : state } ) , dispatch => ( { duck , dispatch } ) ) ( Container ) ; } ; } param autoDestroy root ( autoDestroy = true ) { const duckRuntime = this ; const store = this . store ; return function decorate ( Container ) : any { class AttachedContainer extends Component { componentDidMount ( ) { store . dispatch ( { type : INIT } ) ; if ( super . componentDidMount ) { return super . componentDidMount ( ) ; } } componentWillUnmount ( ) { store . dispatch ( { type : END } ) ; if ( autoDestroy ) { duckRuntime . destroy ( ) ; } if ( super . componentWillUnmount ) { return super . componentWillUnmount ( ) ; } } render ( ) { return createElement ( Container , ( this as any ) . props ) ; } } ( AttachedContainer as any ) . displayName = `duckRoot(${ Container . displayName || Container . name || "Unknown" })` ; return AttachedContainer ; } ; } /**
     * equals to:
     * duckRuntime.connect()(
     *   duckRuntime.root()(Container)
     * )
     * 同时绑定Root及connect
     */ connectRoot ( ) { const decorateRoot = this . root ( ) ; const decorateConnect = this . connect ( ) ; return function decorate ( Container ) { return decorateConnect ( decorateRoot ( Container ) ) ; } ; } }