//tslint:disable-next-line const Symbol = require('es6-symbol'); import * as React from 'react'; import { connect } from 'react-redux'; import { Dispatch } from 'redux'; import { mountComponent, unmountComponent } from '../models/asyncComponentTracker'; // tslint:disable:no-invalid-this // tslint:disable:no-function-expression export const asyncState = (target: new (...args: any[]) => T) => { function outer(...args) { const instance: any = new target(...args); const key = instance.props.asyncKey; if (!instance.key) { Object.defineProperty(instance, 'key', { writable: false, value: key }); } return instance; } outer.prototype = target.prototype; const origMount = target.prototype.componentDidMount; const origUnmount = target.prototype.componentWillUnmount; outer.prototype.componentDidMount = function () { if (origMount) { origMount.apply(this); } mountComponent(this); }; outer.prototype.componentWillUnmount = function () { unmountComponent(this); if (origUnmount) { origUnmount.apply(this); } }; outer.prototype.updateAsyncState = outer.prototype.updateAsyncState || function (next) { this.setState({ asyncState: next }); }; return outer; }; export type MapAttributes = (asyncKey: Symbol) => (store: S) => A; export type MapActions = (asyncKey: Symbol) => (dispatch: Dispatch) => A; export const asyncConnect = (Component: React.ComponentClass | React.FunctionComponent) => (mapAttributes: MapAttributes, mapActions: MapActions) => { const dummyKey = Symbol(); const dummyClass = connect(mapAttributes(dummyKey), mapActions(dummyKey))(Component); // constructor function outter(...args) { const asyncKey = Symbol(); const attributesMapper = mapAttributes(asyncKey); const actionMapper = mapActions(asyncKey); const injected = connect(attributesMapper, actionMapper)(Component); return new injected(...args); } outter.prototype = dummyClass.prototype; outter.contextTypes = dummyClass.contextTypes; outter.childContextTypes = dummyClass.childContextTypes; return outter; };