UNPKG

4.51 kBTypeScriptView Raw
1import React, { Children, Component } from 'react';
2import PropTypes from 'prop-types';
3import { connect, Provider, ReactReduxContext } from 'react-redux';
4import instrument, {
5 EnhancedStore,
6 LiftedState,
7 LiftedStore,
8 Options,
9} from 'redux-devtools-instrument';
10import { Action } from 'redux';
11
12function logError(type: string) {
13 if (type === 'NoStore') {
14 console.error(
15 'Redux DevTools could not render. You must pass the Redux store ' +
16 'to <DevTools> either as a "store" prop or by wrapping it in a ' +
17 '<Provider store={store}>.'
18 );
19 } else {
20 console.error(
21 'Redux DevTools could not render. Did you forget to include ' +
22 'DevTools.instrument() in your store enhancer chain before ' +
23 'using createStore()?'
24 );
25 }
26}
27
28export interface Props<
29 S,
30 A extends Action<unknown>,
31 MonitorState,
32 MonitorAction extends Action<unknown>
33> {
34 store?: EnhancedStore<S, A, MonitorState>;
35}
36
37export type Monitor<
38 S,
39 A extends Action<unknown>,
40 MonitorProps extends LiftedState<S, A, MonitorState>,
41 MonitorState,
42 MonitorAction extends Action<unknown>
43> = React.ReactElement<
44 MonitorProps,
45 React.ComponentType<MonitorProps & LiftedState<S, A, MonitorState>> & {
46 update(
47 monitorProps: MonitorProps,
48 state: MonitorState | undefined,
49 action: MonitorAction
50 ): MonitorState;
51 }
52>;
53
54export default function createDevTools<
55 S,
56 A extends Action<unknown>,
57 MonitorProps extends LiftedState<S, A, MonitorState>,
58 MonitorState,
59 MonitorAction extends Action<unknown>
60>(children: Monitor<S, A, MonitorProps, MonitorState, MonitorAction>) {
61 const monitorElement = Children.only(children);
62 const monitorProps = monitorElement.props;
63 const Monitor = monitorElement.type;
64 const ConnectedMonitor = connect(
65 (state: LiftedState<S, A, MonitorState>) => state
66 )(Monitor as React.ComponentType<any>);
67
68 return class DevTools extends Component<
69 Props<S, A, MonitorState, MonitorAction>
70 > {
71 static contextTypes = {
72 store: PropTypes.object,
73 };
74
75 static propTypes = {
76 store: PropTypes.object,
77 };
78
79 liftedStore?: LiftedStore<S, A, MonitorState>;
80
81 static instrument = (
82 options?: Options<S, A, MonitorState, MonitorAction>
83 ) =>
84 instrument(
85 (state, action) => Monitor.update(monitorProps, state, action),
86 options
87 );
88
89 constructor(
90 props: Props<S, A, MonitorState, MonitorAction>,
91 context: { store?: EnhancedStore<S, A, MonitorState> }
92 ) {
93 super(props, context);
94
95 if (ReactReduxContext) {
96 if (this.props.store && !this.props.store.liftedStore) {
97 logError('NoLiftedStore');
98 }
99 return;
100 }
101
102 if (!props.store && !context.store) {
103 logError('NoStore');
104 return;
105 }
106
107 if (context.store) {
108 this.liftedStore = context.store.liftedStore;
109 } else {
110 this.liftedStore = props.store!.liftedStore;
111 }
112
113 if (!this.liftedStore) {
114 logError('NoLiftedStore');
115 }
116 }
117
118 render() {
119 if (ReactReduxContext) {
120 // For react-redux@6
121 if (this.props.store) {
122 if (!this.props.store.liftedStore) {
123 return null;
124 }
125 return (
126 <Provider store={this.props.store.liftedStore}>
127 <ConnectedMonitor {...monitorProps} />
128 </Provider>
129 );
130 }
131 return (
132 <ReactReduxContext.Consumer>
133 {(props) => {
134 if (!props || !props.store) {
135 logError('NoStore');
136 return null;
137 }
138 if (
139 !((props.store as unknown) as EnhancedStore<S, A, MonitorState>)
140 .liftedStore
141 ) {
142 logError('NoLiftedStore');
143 return null;
144 }
145 return (
146 <Provider
147 store={
148 ((props.store as unknown) as EnhancedStore<
149 S,
150 A,
151 MonitorState
152 >).liftedStore
153 }
154 >
155 <ConnectedMonitor {...monitorProps} />
156 </Provider>
157 );
158 }}
159 </ReactReduxContext.Consumer>
160 );
161 }
162
163 if (!this.liftedStore) {
164 return null;
165 }
166
167 return <ConnectedMonitor {...monitorProps} store={this.liftedStore} />;
168 }
169 };
170}