import React, { Children, Component } from 'react'; import PropTypes from 'prop-types'; import { connect, Provider, ReactReduxContext } from 'react-redux'; import instrument, { EnhancedStore, LiftedState, LiftedStore, Options, } from 'redux-devtools-instrument'; import { Action } from 'redux'; function logError(type: string) { if (type === 'NoStore') { console.error( 'Redux DevTools could not render. You must pass the Redux store ' + 'to either as a "store" prop or by wrapping it in a ' + '.' ); } else { console.error( 'Redux DevTools could not render. Did you forget to include ' + 'DevTools.instrument() in your store enhancer chain before ' + 'using createStore()?' ); } } export interface Props< S, A extends Action, MonitorState, MonitorAction extends Action > { store?: EnhancedStore; } export type Monitor< S, A extends Action, MonitorProps extends LiftedState, MonitorState, MonitorAction extends Action > = React.ReactElement< MonitorProps, React.ComponentType> & { update( monitorProps: MonitorProps, state: MonitorState | undefined, action: MonitorAction ): MonitorState; } >; export default function createDevTools< S, A extends Action, MonitorProps extends LiftedState, MonitorState, MonitorAction extends Action >(children: Monitor) { const monitorElement = Children.only(children); const monitorProps = monitorElement.props; const Monitor = monitorElement.type; const ConnectedMonitor = connect( (state: LiftedState) => state )(Monitor as React.ComponentType); return class DevTools extends Component< Props > { static contextTypes = { store: PropTypes.object, }; static propTypes = { store: PropTypes.object, }; liftedStore?: LiftedStore; static instrument = ( options?: Options ) => instrument( (state, action) => Monitor.update(monitorProps, state, action), options ); constructor( props: Props, context: { store?: EnhancedStore } ) { super(props, context); if (ReactReduxContext) { if (this.props.store && !this.props.store.liftedStore) { logError('NoLiftedStore'); } return; } if (!props.store && !context.store) { logError('NoStore'); return; } if (context.store) { this.liftedStore = context.store.liftedStore; } else { this.liftedStore = props.store!.liftedStore; } if (!this.liftedStore) { logError('NoLiftedStore'); } } render() { if (ReactReduxContext) { // For react-redux@6 if (this.props.store) { if (!this.props.store.liftedStore) { return null; } return ( ); } return ( {(props) => { if (!props || !props.store) { logError('NoStore'); return null; } if ( !((props.store as unknown) as EnhancedStore) .liftedStore ) { logError('NoLiftedStore'); return null; } return ( ).liftedStore } > ); }} ); } if (!this.liftedStore) { return null; } return ; } }; }