mirror of
				https://github.com/reduxjs/redux-devtools.git
				synced 2025-11-04 01:47:25 +03:00 
			
		
		
		
	Allow monitors to have their own reducers
This commit is contained in:
		
							parent
							
								
									a37b30e878
								
							
						
					
					
						commit
						4ac31f985a
					
				| 
						 | 
					@ -26,10 +26,10 @@
 | 
				
			||||||
    "babel-core": "^5.6.18",
 | 
					    "babel-core": "^5.6.18",
 | 
				
			||||||
    "babel-loader": "^5.1.4",
 | 
					    "babel-loader": "^5.1.4",
 | 
				
			||||||
    "node-libs-browser": "^0.5.2",
 | 
					    "node-libs-browser": "^0.5.2",
 | 
				
			||||||
    "react-dock": "0.0.3",
 | 
					    "react-dock": "^0.1.0",
 | 
				
			||||||
    "react-hot-loader": "^1.3.0",
 | 
					    "react-hot-loader": "^1.3.0",
 | 
				
			||||||
    "redux-devtools": "^3.0.0-alpha-1",
 | 
					    "redux-devtools": "^3.0.0-alpha-1",
 | 
				
			||||||
    "redux-devtools-log-monitor": "^1.0.0-alpha",
 | 
					    "redux-devtools-log-monitor": "^1.0.0-alpha-3",
 | 
				
			||||||
    "webpack": "^1.9.11",
 | 
					    "webpack": "^1.9.11",
 | 
				
			||||||
    "webpack-dev-server": "^1.9.0"
 | 
					    "webpack-dev-server": "^1.9.0"
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -2,10 +2,13 @@ import { createStore, applyMiddleware, compose } from 'redux';
 | 
				
			||||||
import { devTools, persistState } from 'redux-devtools';
 | 
					import { devTools, persistState } from 'redux-devtools';
 | 
				
			||||||
import thunk from 'redux-thunk';
 | 
					import thunk from 'redux-thunk';
 | 
				
			||||||
import rootReducer from '../reducers';
 | 
					import rootReducer from '../reducers';
 | 
				
			||||||
 | 
					import { createMonitorReducer } from 'redux-devtools-log-monitor';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const finalCreateStore = compose(
 | 
					const finalCreateStore = compose(
 | 
				
			||||||
  applyMiddleware(thunk),
 | 
					  applyMiddleware(thunk),
 | 
				
			||||||
  devTools(),
 | 
					  devTools(createMonitorReducer({
 | 
				
			||||||
 | 
					    isVisibleOnLoad: true
 | 
				
			||||||
 | 
					  })),
 | 
				
			||||||
  persistState(window.location.href.match(/[?&]debug_session=([^&]+)\b/))
 | 
					  persistState(window.location.href.match(/[?&]debug_session=([^&]+)\b/))
 | 
				
			||||||
)(createStore);
 | 
					)(createStore);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -50,10 +50,10 @@
 | 
				
			||||||
    "webpack": "^1.11.0"
 | 
					    "webpack": "^1.11.0"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "peerDependencies": {
 | 
					  "peerDependencies": {
 | 
				
			||||||
    "redux": "^2.0.0 || ^3.0.0"
 | 
					    "redux": "^3.0.0"
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "dependencies": {
 | 
					  "dependencies": {
 | 
				
			||||||
    "react-redux": "^3.0.0",
 | 
					    "react-redux": "^3.0.0",
 | 
				
			||||||
    "redux": "^2.0.0 || ^3.0.0"
 | 
					    "redux": "^3.0.0"
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,9 +1,20 @@
 | 
				
			||||||
import React, { Component } from 'react';
 | 
					import React, { Component } from 'react';
 | 
				
			||||||
import { connect } from 'react-redux';
 | 
					import { connect } from 'react-redux';
 | 
				
			||||||
 | 
					import { bindActionCreators } from 'redux';
 | 
				
			||||||
import { ActionCreators } from './devTools';
 | 
					import { ActionCreators } from './devTools';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default function connectMonitor(Monitor) {
 | 
					export default function connectMonitor(monitorActionCreators = {}) {
 | 
				
			||||||
  const ConnectedMonitor = connect(state => state, ActionCreators)(Monitor);
 | 
					  return Monitor => {
 | 
				
			||||||
 | 
					    function mapStateToProps(state) {
 | 
				
			||||||
 | 
					      return state;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    function mapDispatchToProps(dispatch) {
 | 
				
			||||||
 | 
					      return {
 | 
				
			||||||
 | 
					        ...bindActionCreators(ActionCreators, dispatch),
 | 
				
			||||||
 | 
					        monitorActions: bindActionCreators(monitorActionCreators, dispatch)
 | 
				
			||||||
 | 
					      };
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    const ConnectedMonitor = connect(mapStateToProps, mapDispatchToProps)(Monitor);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    class DevTools extends Component {
 | 
					    class DevTools extends Component {
 | 
				
			||||||
      static Monitor = Monitor;
 | 
					      static Monitor = Monitor;
 | 
				
			||||||
| 
						 | 
					@ -39,4 +50,5 @@ export default function connectMonitor(Monitor) {
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return DevTools;
 | 
					    return DevTools;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -6,7 +6,6 @@ const ActionTypes = {
 | 
				
			||||||
  SWEEP: 'SWEEP',
 | 
					  SWEEP: 'SWEEP',
 | 
				
			||||||
  TOGGLE_ACTION: 'TOGGLE_ACTION',
 | 
					  TOGGLE_ACTION: 'TOGGLE_ACTION',
 | 
				
			||||||
  JUMP_TO_STATE: 'JUMP_TO_STATE',
 | 
					  JUMP_TO_STATE: 'JUMP_TO_STATE',
 | 
				
			||||||
  SET_MONITOR_STATE: 'SET_MONITOR_STATE',
 | 
					 | 
				
			||||||
  RECOMPUTE_STATES: 'RECOMPUTE_STATES'
 | 
					  RECOMPUTE_STATES: 'RECOMPUTE_STATES'
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -79,15 +78,13 @@ function recomputeStates(reducer, committedState, stagedActions, skippedActions)
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Lifts the app state reducer into a DevTools state reducer.
 | 
					 * Lifts the app state reducer into a DevTools state reducer.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
function liftReducer(reducer, initialState) {
 | 
					function liftReducer(reducer, monitorStateReducer, initialState) {
 | 
				
			||||||
  const initialLiftedState = {
 | 
					  const initialLiftedState = {
 | 
				
			||||||
    committedState: initialState,
 | 
					    committedState: initialState,
 | 
				
			||||||
    stagedActions: [INIT_ACTION],
 | 
					    stagedActions: [INIT_ACTION],
 | 
				
			||||||
    skippedActions: {},
 | 
					    skippedActions: {},
 | 
				
			||||||
    currentStateIndex: 0,
 | 
					    currentStateIndex: 0,
 | 
				
			||||||
    monitorState: {
 | 
					    monitorState: monitorStateReducer(undefined, INIT_ACTION),
 | 
				
			||||||
      isVisible: true
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    timestamps: [Date.now()]
 | 
					    timestamps: [Date.now()]
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -145,9 +142,6 @@ function liftReducer(reducer, initialState) {
 | 
				
			||||||
      stagedActions = [...stagedActions, liftedAction.action];
 | 
					      stagedActions = [...stagedActions, liftedAction.action];
 | 
				
			||||||
      timestamps = [...timestamps, liftedAction.timestamp];
 | 
					      timestamps = [...timestamps, liftedAction.timestamp];
 | 
				
			||||||
      break;
 | 
					      break;
 | 
				
			||||||
    case ActionTypes.SET_MONITOR_STATE:
 | 
					 | 
				
			||||||
      monitorState = liftedAction.monitorState;
 | 
					 | 
				
			||||||
      break;
 | 
					 | 
				
			||||||
    case ActionTypes.RECOMPUTE_STATES:
 | 
					    case ActionTypes.RECOMPUTE_STATES:
 | 
				
			||||||
      stagedActions = liftedAction.stagedActions;
 | 
					      stagedActions = liftedAction.stagedActions;
 | 
				
			||||||
      timestamps = liftedAction.timestamps;
 | 
					      timestamps = liftedAction.timestamps;
 | 
				
			||||||
| 
						 | 
					@ -166,6 +160,8 @@ function liftReducer(reducer, initialState) {
 | 
				
			||||||
      skippedActions
 | 
					      skippedActions
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    monitorState = monitorStateReducer(monitorState, liftedAction);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return {
 | 
					    return {
 | 
				
			||||||
      committedState,
 | 
					      committedState,
 | 
				
			||||||
      stagedActions,
 | 
					      stagedActions,
 | 
				
			||||||
| 
						 | 
					@ -202,7 +198,7 @@ function unliftState(liftedState) {
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Unlifts the DevTools store to act like the app's store.
 | 
					 * Unlifts the DevTools store to act like the app's store.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
function unliftStore(liftedStore, reducer) {
 | 
					function unliftStore(liftedStore, monitorStateReducer) {
 | 
				
			||||||
  let lastDefinedState;
 | 
					  let lastDefinedState;
 | 
				
			||||||
  return {
 | 
					  return {
 | 
				
			||||||
    ...liftedStore,
 | 
					    ...liftedStore,
 | 
				
			||||||
| 
						 | 
					@ -218,11 +214,8 @@ function unliftStore(liftedStore, reducer) {
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
      return lastDefinedState;
 | 
					      return lastDefinedState;
 | 
				
			||||||
    },
 | 
					    },
 | 
				
			||||||
    getReducer() {
 | 
					 | 
				
			||||||
      return reducer;
 | 
					 | 
				
			||||||
    },
 | 
					 | 
				
			||||||
    replaceReducer(nextReducer) {
 | 
					    replaceReducer(nextReducer) {
 | 
				
			||||||
      liftedStore.replaceReducer(liftReducer(nextReducer));
 | 
					      liftedStore.replaceReducer(liftReducer(nextReducer, monitorStateReducer));
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					@ -249,9 +242,6 @@ export const ActionCreators = {
 | 
				
			||||||
  jumpToState(index) {
 | 
					  jumpToState(index) {
 | 
				
			||||||
    return { type: ActionTypes.JUMP_TO_STATE, index };
 | 
					    return { type: ActionTypes.JUMP_TO_STATE, index };
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  setMonitorState(monitorState) {
 | 
					 | 
				
			||||||
    return { type: ActionTypes.SET_MONITOR_STATE, monitorState };
 | 
					 | 
				
			||||||
  },
 | 
					 | 
				
			||||||
  recomputeStates(committedState, stagedActions) {
 | 
					  recomputeStates(committedState, stagedActions) {
 | 
				
			||||||
    return {
 | 
					    return {
 | 
				
			||||||
      type: ActionTypes.RECOMPUTE_STATES,
 | 
					      type: ActionTypes.RECOMPUTE_STATES,
 | 
				
			||||||
| 
						 | 
					@ -264,11 +254,11 @@ export const ActionCreators = {
 | 
				
			||||||
/**
 | 
					/**
 | 
				
			||||||
 * Redux DevTools middleware.
 | 
					 * Redux DevTools middleware.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
export default function devTools() {
 | 
					export default function devTools(monitorStateReducer = () => undefined) {
 | 
				
			||||||
  return next => (reducer, initialState) => {
 | 
					  return next => (reducer, initialState) => {
 | 
				
			||||||
    const liftedReducer = liftReducer(reducer, initialState);
 | 
					    const liftedReducer = liftReducer(reducer, monitorStateReducer, initialState);
 | 
				
			||||||
    const liftedStore = next(liftedReducer);
 | 
					    const liftedStore = next(liftedReducer);
 | 
				
			||||||
    const store = unliftStore(liftedStore, reducer);
 | 
					    const store = unliftStore(liftedStore, monitorStateReducer);
 | 
				
			||||||
    return store;
 | 
					    return store;
 | 
				
			||||||
  };
 | 
					  };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,12 +11,25 @@ class MockMonitor extends Component {
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function increment() {
 | 
				
			||||||
 | 
					  return { type: 'INCREMENT' };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					function mockMonitorReducer(state = 0, action) {
 | 
				
			||||||
 | 
					  switch (action.type) {
 | 
				
			||||||
 | 
					  case 'INCREMENT':
 | 
				
			||||||
 | 
					    return state + 1;
 | 
				
			||||||
 | 
					  default:
 | 
				
			||||||
 | 
					    return state;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
describe('connectMonitor', () => {
 | 
					describe('connectMonitor', () => {
 | 
				
			||||||
  jsdom();
 | 
					  jsdom();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  it('should pass devToolsStore to monitor', () => {
 | 
					  it('should pass devToolsStore to monitor', () => {
 | 
				
			||||||
    const store = devTools()(createStore)(() => {});
 | 
					    const store = devTools()(createStore)(() => {});
 | 
				
			||||||
    const ConnectedMonitor = connectMonitor(MockMonitor);
 | 
					    const ConnectedMonitor = connectMonitor()(MockMonitor);
 | 
				
			||||||
    const tree = TestUtils.renderIntoDocument(
 | 
					    const tree = TestUtils.renderIntoDocument(
 | 
				
			||||||
      <ConnectedMonitor store={store} />
 | 
					      <ConnectedMonitor store={store} />
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
| 
						 | 
					@ -26,7 +39,7 @@ describe('connectMonitor', () => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  it('should pass props to monitor', () => {
 | 
					  it('should pass props to monitor', () => {
 | 
				
			||||||
    const store = devTools()(createStore)(() => {});
 | 
					    const store = devTools()(createStore)(() => {});
 | 
				
			||||||
    const ConnectedMonitor = connectMonitor(MockMonitor);
 | 
					    const ConnectedMonitor = connectMonitor()(MockMonitor);
 | 
				
			||||||
    const tree = TestUtils.renderIntoDocument(
 | 
					    const tree = TestUtils.renderIntoDocument(
 | 
				
			||||||
      <ConnectedMonitor store={store} one={1} two={2}/>
 | 
					      <ConnectedMonitor store={store} one={1} two={2}/>
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
| 
						 | 
					@ -36,7 +49,7 @@ describe('connectMonitor', () => {
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  it('should subscribe monitor to store updates', () => {
 | 
					  it('should subscribe monitor to store updates', () => {
 | 
				
			||||||
    const ConnectedMonitor = connectMonitor(MockMonitor);
 | 
					    const ConnectedMonitor = connectMonitor()(MockMonitor);
 | 
				
			||||||
    const store = devTools()(createStore)(
 | 
					    const store = devTools()(createStore)(
 | 
				
			||||||
      (state, action) => {
 | 
					      (state, action) => {
 | 
				
			||||||
        switch (action.type) {
 | 
					        switch (action.type) {
 | 
				
			||||||
| 
						 | 
					@ -63,7 +76,7 @@ describe('connectMonitor', () => {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  it('should warn if devTools() not in middleware', () => {
 | 
					  it('should warn if devTools() not in middleware', () => {
 | 
				
			||||||
    const store = createStore(() => {});
 | 
					    const store = createStore(() => {});
 | 
				
			||||||
    const ConnectedMonitor = connectMonitor(MockMonitor);
 | 
					    const ConnectedMonitor = connectMonitor()(MockMonitor);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // Force to re-evaluate propType checks on every run
 | 
					    // Force to re-evaluate propType checks on every run
 | 
				
			||||||
    ConnectedMonitor.displayName = Math.random().toString();
 | 
					    ConnectedMonitor.displayName = Math.random().toString();
 | 
				
			||||||
| 
						 | 
					@ -77,4 +90,27 @@ describe('connectMonitor', () => {
 | 
				
			||||||
      (call, errMsg) => call.arguments[0].match(errMsg)
 | 
					      (call, errMsg) => call.arguments[0].match(errMsg)
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it('should pass monitor state and actions to the monitor', () => {
 | 
				
			||||||
 | 
					    const store = devTools(mockMonitorReducer)(createStore)(() => {});
 | 
				
			||||||
 | 
					    const ConnectedMonitor = connectMonitor()(MockMonitor);
 | 
				
			||||||
 | 
					    const tree = TestUtils.renderIntoDocument(
 | 
				
			||||||
 | 
					      <ConnectedMonitor store={store} />
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					    const mockMonitor = TestUtils.findRenderedComponentWithType(tree, MockMonitor);
 | 
				
			||||||
 | 
					    expect(mockMonitor.props.monitorState).toBe(0);
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  it('should pass bound monitor actions to monitor', () => {
 | 
				
			||||||
 | 
					    const ConnectedMonitor = connectMonitor({ increment })(MockMonitor);
 | 
				
			||||||
 | 
					    const store = devTools(mockMonitorReducer)(createStore)(() => {});
 | 
				
			||||||
 | 
					    const tree = TestUtils.renderIntoDocument(
 | 
				
			||||||
 | 
					      <ConnectedMonitor store={store} />
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    const mockMonitor = TestUtils.findRenderedComponentWithType(tree, MockMonitor);
 | 
				
			||||||
 | 
					    expect(mockMonitor.props.monitorState).toBe(0);
 | 
				
			||||||
 | 
					    mockMonitor.props.monitorActions.increment();
 | 
				
			||||||
 | 
					    expect(mockMonitor.props.monitorState).toBe(1);
 | 
				
			||||||
 | 
					  });
 | 
				
			||||||
});
 | 
					});
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -143,11 +143,6 @@ describe('devTools', () => {
 | 
				
			||||||
    expect(store.getState()).toBe(2);
 | 
					    expect(store.getState()).toBe(2);
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  it('should set monitor state', () => {
 | 
					 | 
				
			||||||
    devToolsStore.dispatch(ActionCreators.setMonitorState({test: 'test'}));
 | 
					 | 
				
			||||||
    expect(devToolsStore.getState().monitorState.test).toBe('test');
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  it('should recompute', () => {
 | 
					  it('should recompute', () => {
 | 
				
			||||||
    store.dispatch({ type: 'INCREMENT' });
 | 
					    store.dispatch({ type: 'INCREMENT' });
 | 
				
			||||||
    store.dispatch({ type: 'DECREMENT' });
 | 
					    store.dispatch({ type: 'DECREMENT' });
 | 
				
			||||||
| 
						 | 
					@ -167,10 +162,6 @@ describe('devTools', () => {
 | 
				
			||||||
    expect(store.getState()).toBe(13);
 | 
					    expect(store.getState()).toBe(13);
 | 
				
			||||||
  });
 | 
					  });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  it('should get the reducer', () => {
 | 
					 | 
				
			||||||
    expect(store.getReducer()).toBe(counter);
 | 
					 | 
				
			||||||
  });
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
  it('should replace the reducer', () => {
 | 
					  it('should replace the reducer', () => {
 | 
				
			||||||
    store.dispatch({ type: 'INCREMENT' });
 | 
					    store.dispatch({ type: 'INCREMENT' });
 | 
				
			||||||
    store.dispatch({ type: 'DECREMENT' });
 | 
					    store.dispatch({ type: 'DECREMENT' });
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in New Issue
	
	Block a user