mirror of
https://github.com/reduxjs/redux-devtools.git
synced 2024-11-22 09:36:43 +03:00
Explicit > implicit
This commit is contained in:
parent
b2210f161c
commit
4375d69d5e
10
examples/counter/src/containers/DevTools.js
Normal file
10
examples/counter/src/containers/DevTools.js
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
import React from 'react';
|
||||||
|
import { createDevTools } from 'redux-devtools';
|
||||||
|
import createLogMonitor from 'redux-devtools-log-monitor';
|
||||||
|
import createDockMonitor from '../dock/DockMonitor';
|
||||||
|
|
||||||
|
export default createDevTools(
|
||||||
|
createDockMonitor(
|
||||||
|
createLogMonitor()
|
||||||
|
)
|
||||||
|
);
|
|
@ -1,24 +1,18 @@
|
||||||
import React, { Component } from 'react';
|
import React, { Component } from 'react';
|
||||||
import { Provider } from 'react-redux';
|
import { Provider } from 'react-redux';
|
||||||
import { DevToolsProvider } from 'redux-devtools';
|
|
||||||
import CounterApp from './CounterApp';
|
import CounterApp from './CounterApp';
|
||||||
import LogMonitor from 'redux-devtools-log-monitor';
|
import DevTools from './DevTools';
|
||||||
import DockMonitor from '../dock/DockMonitor';
|
|
||||||
|
|
||||||
export default class Root extends Component {
|
export default class Root extends Component {
|
||||||
render() {
|
render() {
|
||||||
const { store } = this.props;
|
const { store } = this.props;
|
||||||
return (
|
return (
|
||||||
<div>
|
|
||||||
<Provider store={store}>
|
<Provider store={store}>
|
||||||
|
<div>
|
||||||
<CounterApp />
|
<CounterApp />
|
||||||
</Provider>
|
<DevTools />
|
||||||
<DevToolsProvider store={store}>
|
|
||||||
<DockMonitor>
|
|
||||||
<LogMonitor />
|
|
||||||
</DockMonitor>
|
|
||||||
</DevToolsProvider>
|
|
||||||
</div>
|
</div>
|
||||||
|
</Provider>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,65 +4,23 @@
|
||||||
|
|
||||||
import React, { Component, PropTypes } from 'react';
|
import React, { Component, PropTypes } from 'react';
|
||||||
import Dock from 'react-dock';
|
import Dock from 'react-dock';
|
||||||
import MapProvider from './MapProvider';
|
|
||||||
import { connect } from 'react-redux';
|
import { connect } from 'react-redux';
|
||||||
import { combineReducers } from 'redux';
|
import { combineReducers, bindActionCreators } from 'redux';
|
||||||
|
|
||||||
const TOGGLE_VISIBILITY = '@@redux-devtools/dock/TOGGLE_VISIBILITY';
|
|
||||||
function toggleVisibility() {
|
|
||||||
return { type: TOGGLE_VISIBILITY };
|
|
||||||
}
|
|
||||||
|
|
||||||
const CHANGE_POSITION = '@@redux-devtools/dock/CHANGE_POSITION';
|
|
||||||
function changePosition() {
|
|
||||||
return { type: CHANGE_POSITION };
|
|
||||||
}
|
|
||||||
|
|
||||||
const POSITIONS = ['left', 'top', 'right', 'bottom'];
|
const POSITIONS = ['left', 'top', 'right', 'bottom'];
|
||||||
|
|
||||||
function wrapReducer(options = {}) {
|
class DockMonitor extends Component {
|
||||||
const {
|
|
||||||
isVisible: initialIsVisible = true,
|
|
||||||
position: initialPosition = 'right'
|
|
||||||
} = options;
|
|
||||||
|
|
||||||
function position(state = initialPosition, action) {
|
|
||||||
return (action.type === CHANGE_POSITION) ?
|
|
||||||
POSITIONS[(POSITIONS.indexOf(state) + 1) % POSITIONS.length] :
|
|
||||||
state;
|
|
||||||
}
|
|
||||||
|
|
||||||
function isVisible(state = initialIsVisible, action) {
|
|
||||||
return (action.type === TOGGLE_VISIBILITY) ?
|
|
||||||
!state :
|
|
||||||
state;
|
|
||||||
}
|
|
||||||
|
|
||||||
return childMonitorReducer => combineReducers({
|
|
||||||
childMonitorState: childMonitorReducer,
|
|
||||||
position,
|
|
||||||
isVisible
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
function mapUpstreamStateToDownstreamState(state) {
|
|
||||||
return {
|
|
||||||
devToolsState: state.devToolsState,
|
|
||||||
monitorState: state.monitorState.childMonitorState
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
@connect(
|
|
||||||
state => state.monitorState,
|
|
||||||
{ toggleVisibility, changePosition }
|
|
||||||
)
|
|
||||||
export default class DockMonitor extends Component {
|
|
||||||
static propTypes = {
|
static propTypes = {
|
||||||
position: PropTypes.oneOf(['left', 'top', 'right', 'bottom']).isRequired,
|
monitorState: PropTypes.shape({
|
||||||
|
position: PropTypes.oneOf(POSITIONS).isRequired,
|
||||||
isVisible: PropTypes.bool.isRequired,
|
isVisible: PropTypes.bool.isRequired,
|
||||||
childMonitorState: PropTypes.any,
|
childState: PropTypes.any
|
||||||
|
}).isRequired,
|
||||||
|
|
||||||
|
monitorActions: PropTypes.shape({
|
||||||
toggleVisibility: PropTypes.func.isRequired,
|
toggleVisibility: PropTypes.func.isRequired,
|
||||||
changePosition: PropTypes.func.isRequired
|
changePosition: PropTypes.func.isRequired
|
||||||
|
}).isRequired
|
||||||
};
|
};
|
||||||
|
|
||||||
componentDidMount() {
|
componentDidMount() {
|
||||||
|
@ -84,10 +42,10 @@ export default class DockMonitor extends Component {
|
||||||
const char = String.fromCharCode(key);
|
const char = String.fromCharCode(key);
|
||||||
switch (char) {
|
switch (char) {
|
||||||
case 'H':
|
case 'H':
|
||||||
this.props.toggleVisibility();
|
this.props.monitorActions.toggleVisibility();
|
||||||
break;
|
break;
|
||||||
case 'D':
|
case 'D':
|
||||||
this.props.changePosition();
|
this.props.monitorActions.changePosition();
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
|
@ -95,17 +53,75 @@ export default class DockMonitor extends Component {
|
||||||
}
|
}
|
||||||
|
|
||||||
render() {
|
render() {
|
||||||
const { position, isVisible, children } = this.props;
|
const { children, monitorState } = this.props;
|
||||||
|
const { position, isVisible } = monitorState;
|
||||||
return (
|
return (
|
||||||
<Dock position={position}
|
<Dock position={position}
|
||||||
isVisible={isVisible}
|
isVisible={isVisible}
|
||||||
dimMode='none'>
|
dimMode='none'>
|
||||||
<MapProvider mapState={mapUpstreamStateToDownstreamState}>
|
|
||||||
{children}
|
{children}
|
||||||
</MapProvider>
|
|
||||||
</Dock>
|
</Dock>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DockMonitor.wrapReducer = wrapReducer;
|
const TOGGLE_VISIBILITY = '@@redux-devtools/dock/TOGGLE_VISIBILITY';
|
||||||
|
function toggleVisibility() {
|
||||||
|
return { type: TOGGLE_VISIBILITY };
|
||||||
|
}
|
||||||
|
|
||||||
|
const CHANGE_POSITION = '@@redux-devtools/dock/CHANGE_POSITION';
|
||||||
|
function changePosition() {
|
||||||
|
return { type: CHANGE_POSITION };
|
||||||
|
}
|
||||||
|
|
||||||
|
export default function create(ChildMonitor, {
|
||||||
|
defaultIsVisible = true,
|
||||||
|
defaultPosition = 'right'
|
||||||
|
} = {}) {
|
||||||
|
function position(state = defaultPosition, action) {
|
||||||
|
return (action.type === CHANGE_POSITION) ?
|
||||||
|
POSITIONS[(POSITIONS.indexOf(state) + 1) % POSITIONS.length] :
|
||||||
|
state;
|
||||||
|
}
|
||||||
|
|
||||||
|
function isVisible(state = defaultIsVisible, action) {
|
||||||
|
return (action.type === TOGGLE_VISIBILITY) ?
|
||||||
|
!state :
|
||||||
|
state;
|
||||||
|
}
|
||||||
|
|
||||||
|
function getChildStore(store) {
|
||||||
|
return {
|
||||||
|
...store,
|
||||||
|
getState() {
|
||||||
|
const state = store.getState();
|
||||||
|
return {
|
||||||
|
...state,
|
||||||
|
monitorState: state.monitorState.childState
|
||||||
|
};
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const Monitor = connect(
|
||||||
|
state => state,
|
||||||
|
dispatch => ({
|
||||||
|
monitorActions: bindActionCreators({ toggleVisibility, changePosition }, dispatch)
|
||||||
|
})
|
||||||
|
)(DockMonitor);
|
||||||
|
|
||||||
|
const CompositeMonitor = ({ store }) => (
|
||||||
|
<Monitor store={store}>
|
||||||
|
<ChildMonitor store={getChildStore(store)} />
|
||||||
|
</Monitor>
|
||||||
|
);
|
||||||
|
|
||||||
|
CompositeMonitor.reducer = combineReducers({
|
||||||
|
childState: ChildMonitor.reducer,
|
||||||
|
position,
|
||||||
|
isVisible
|
||||||
|
});
|
||||||
|
|
||||||
|
return CompositeMonitor;
|
||||||
|
}
|
|
@ -1,52 +0,0 @@
|
||||||
//
|
|
||||||
// TODO: extract to a separate project.
|
|
||||||
//
|
|
||||||
|
|
||||||
import { Children, Component, PropTypes } from 'react';
|
|
||||||
|
|
||||||
const identity = _ => _;
|
|
||||||
function mapStore(store, { mapAction = identity, mapState = identity }) {
|
|
||||||
return {
|
|
||||||
...store,
|
|
||||||
dispatch(action) {
|
|
||||||
return store.dispatch(mapAction(action));
|
|
||||||
},
|
|
||||||
subscribe(listener) {
|
|
||||||
return store.subscribe(listener);
|
|
||||||
},
|
|
||||||
getState() {
|
|
||||||
return mapState(store.getState());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export default class MapProvider extends Component {
|
|
||||||
static propTypes = {
|
|
||||||
mapAction: PropTypes.func,
|
|
||||||
mapState: PropTypes.func
|
|
||||||
};
|
|
||||||
|
|
||||||
static contextTypes = {
|
|
||||||
store: PropTypes.object.isRequired
|
|
||||||
};
|
|
||||||
|
|
||||||
static childContextTypes = {
|
|
||||||
store: PropTypes.object.isRequired
|
|
||||||
};
|
|
||||||
|
|
||||||
getChildContext() {
|
|
||||||
return {
|
|
||||||
store: this.store
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
constructor(props, context) {
|
|
||||||
super(props, context);
|
|
||||||
this.store = mapStore(context.store, props);
|
|
||||||
}
|
|
||||||
|
|
||||||
render() {
|
|
||||||
return Children.only(this.props.children);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -1,23 +1,12 @@
|
||||||
import { createStore, applyMiddleware, compose } from 'redux';
|
import { createStore, applyMiddleware, compose } from 'redux';
|
||||||
import devTools, { persistState } from 'redux-devtools';
|
import { persistState } from 'redux-devtools';
|
||||||
import thunk from 'redux-thunk';
|
import thunk from 'redux-thunk';
|
||||||
import rootReducer from '../reducers';
|
import rootReducer from '../reducers';
|
||||||
import DockMonitor from '../dock/DockMonitor';
|
import DevTools from '../containers/DevTools';
|
||||||
import LogMonitor from 'redux-devtools-log-monitor';
|
|
||||||
|
|
||||||
const finalCreateStore = compose(
|
const finalCreateStore = compose(
|
||||||
applyMiddleware(
|
applyMiddleware(thunk),
|
||||||
thunk
|
DevTools.enhance,
|
||||||
),
|
|
||||||
devTools(
|
|
||||||
LogMonitor.createReducer({
|
|
||||||
preserveScrollTop: true
|
|
||||||
}),
|
|
||||||
DockMonitor.wrapReducer({
|
|
||||||
position: 'right',
|
|
||||||
isVisible: true
|
|
||||||
})
|
|
||||||
),
|
|
||||||
persistState(
|
persistState(
|
||||||
window.location.href.match(
|
window.location.href.match(
|
||||||
/[?&]debug_session=([^&]+)\b/
|
/[?&]debug_session=([^&]+)\b/
|
||||||
|
|
|
@ -1,37 +0,0 @@
|
||||||
import React, { Component } from 'react';
|
|
||||||
import { Provider } from 'react-redux';
|
|
||||||
|
|
||||||
export default class DevToolsProvider extends Component {
|
|
||||||
static propTypes = {
|
|
||||||
store(props, propName, componentName) {
|
|
||||||
if (!props.store) {
|
|
||||||
return new Error('Required prop `store` was not specified in `' + componentName + '`.');
|
|
||||||
}
|
|
||||||
if (!props.store.devToolsStore) {
|
|
||||||
return new Error(
|
|
||||||
'Could not find the DevTools store inside the `store` prop passed to `' +
|
|
||||||
componentName +
|
|
||||||
'`. Have you applied the devTools() store enhancer?'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
render() {
|
|
||||||
const { store, children } = this.props;
|
|
||||||
if (!store) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
const { devToolsStore } = store;
|
|
||||||
if (!devToolsStore) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
return (
|
|
||||||
<Provider store={devToolsStore}>
|
|
||||||
{children}
|
|
||||||
</Provider>
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
17
src/createDevTools.js
Normal file
17
src/createDevTools.js
Normal file
|
@ -0,0 +1,17 @@
|
||||||
|
import React, { cloneElement, Component, PropTypes } from 'react';
|
||||||
|
import enhance from './enhance';
|
||||||
|
|
||||||
|
export default function createDevTools(Monitor) {
|
||||||
|
return class DevTools extends Component {
|
||||||
|
static contextTypes = {
|
||||||
|
store: PropTypes.object.isRequired
|
||||||
|
};
|
||||||
|
|
||||||
|
static enhance = enhance(Monitor.reducer);
|
||||||
|
|
||||||
|
render() {
|
||||||
|
return <Monitor store={this.context.store.devToolsStore} />;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -264,18 +264,11 @@ export const ActionCreators = {
|
||||||
/**
|
/**
|
||||||
* Redux DevTools store enhancer.
|
* Redux DevTools store enhancer.
|
||||||
*/
|
*/
|
||||||
export default function devTools(
|
export default function enhance(monitorReducer = () => null) {
|
||||||
monitorReducer = () => null,
|
|
||||||
...monitorReducerWrappers
|
|
||||||
) {
|
|
||||||
return next => (reducer, initialState) => {
|
return next => (reducer, initialState) => {
|
||||||
const finalMonitorReducer = compose(
|
|
||||||
...monitorReducerWrappers.slice().reverse()
|
|
||||||
)(monitorReducer);
|
|
||||||
|
|
||||||
const wrapReducer = (r) => combineReducers({
|
const wrapReducer = (r) => combineReducers({
|
||||||
devToolsState: createDevToolsStateReducer(r, initialState),
|
devToolsState: createDevToolsStateReducer(r, initialState),
|
||||||
monitorState: finalMonitorReducer
|
monitorState: monitorReducer
|
||||||
});
|
});
|
||||||
|
|
||||||
const devToolsStore = next(wrapReducer(reducer));
|
const devToolsStore = next(wrapReducer(reducer));
|
|
@ -1,3 +1,3 @@
|
||||||
export { default, ActionCreators, ActionTypes } from './devTools';
|
export { default, ActionCreators, ActionTypes } from './enhance';
|
||||||
export { default as DevToolsProvider } from './DevToolsProvider';
|
|
||||||
export { default as persistState } from './persistState';
|
export { default as persistState } from './persistState';
|
||||||
|
export { default as createDevTools } from './createDevTools';
|
||||||
|
|
Loading…
Reference in New Issue
Block a user