Skip to content

Commit 2138ca6

Browse files
committed
Connect once at the top
1 parent 4375d69 commit 2138ca6

File tree

5 files changed

+83
-40
lines changed

5 files changed

+83
-40
lines changed

examples/counter/src/dock/DockMonitor.js

Lines changed: 24 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,7 @@
44

55
import React, { Component, PropTypes } from 'react';
66
import Dock from 'react-dock';
7-
import { connect } from 'react-redux';
8-
import { combineReducers, bindActionCreators } from 'redux';
7+
import { combineReducers } from 'redux';
98

109
const POSITIONS = ['left', 'top', 'right', 'bottom'];
1110

@@ -14,7 +13,7 @@ class DockMonitor extends Component {
1413
monitorState: PropTypes.shape({
1514
position: PropTypes.oneOf(POSITIONS).isRequired,
1615
isVisible: PropTypes.bool.isRequired,
17-
childState: PropTypes.any
16+
child: PropTypes.any
1817
}).isRequired,
1918

2019
monitorActions: PropTypes.shape({
@@ -75,7 +74,7 @@ function changePosition() {
7574
return { type: CHANGE_POSITION };
7675
}
7776

78-
export default function create(ChildMonitor, {
77+
export default function create(child, {
7978
defaultIsVisible = true,
8079
defaultPosition = 'right'
8180
} = {}) {
@@ -91,37 +90,27 @@ export default function create(ChildMonitor, {
9190
state;
9291
}
9392

94-
function getChildStore(store) {
95-
return {
96-
...store,
97-
getState() {
98-
const state = store.getState();
99-
return {
100-
...state,
101-
monitorState: state.monitorState.childState
102-
};
103-
}
104-
};
105-
}
106-
107-
const Monitor = connect(
108-
state => state,
109-
dispatch => ({
110-
monitorActions: bindActionCreators({ toggleVisibility, changePosition }, dispatch)
111-
})
112-
)(DockMonitor);
113-
114-
const CompositeMonitor = ({ store }) => (
115-
<Monitor store={store}>
116-
<ChildMonitor store={getChildStore(store)} />
117-
</Monitor>
93+
const ChildMonitor = child.component;
94+
const CompositeMonitor = ({ monitorState, monitorActions, ...rest }) => (
95+
<DockMonitor monitorState={monitorState}
96+
monitorActions={monitorActions}>
97+
<ChildMonitor {...rest}
98+
monitorState={monitorState.child}
99+
monitorActions={monitorActions.child} />
100+
</DockMonitor>
118101
);
119102

120-
CompositeMonitor.reducer = combineReducers({
121-
childState: ChildMonitor.reducer,
122-
position,
123-
isVisible
124-
});
125-
126-
return CompositeMonitor;
103+
return {
104+
component: CompositeMonitor,
105+
reducer: combineReducers({
106+
position,
107+
isVisible,
108+
child: child.reducer
109+
}),
110+
actionCreators: {
111+
toggleVisibility,
112+
changePosition,
113+
child: child.actionCreators
114+
}
115+
};
127116
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { bindActionCreators } from 'redux';
2+
3+
export default function bindActionCreatorsRecursively(actionCreators, dispatch) {
4+
return Object.keys(actionCreators).reduce((result, key) => {
5+
if (!actionCreators[key]) {
6+
return result;
7+
}
8+
switch (typeof actionCreators[key]) {
9+
case 'object':
10+
result[key] = bindActionCreatorsRecursively(actionCreators[key], dispatch);
11+
break;
12+
case 'function':
13+
result[key] = bindActionCreators(actionCreators[key], dispatch);
14+
break;
15+
default:
16+
break;
17+
}
18+
return result;
19+
}, {});
20+
}

src/connectMonitor.js

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import { bindActionCreators } from 'redux';
2+
import bindActionCreatorsRecursively from './bindActionCreatorsRecursively';
3+
import { connect } from 'react-redux';
4+
import { ActionCreators as devToolsActionCreators } from './enhance';
5+
6+
export default function connectMonitor({
7+
component,
8+
reducer = () => null,
9+
actionCreators = {}
10+
}) {
11+
function mapStateToProps(state) {
12+
return {
13+
devToolsState: state.devToolsState,
14+
monitorState: state.monitorState
15+
};
16+
}
17+
18+
function mapDispatchToProps(dispatch) {
19+
return {
20+
devToolsActions: bindActionCreators(devToolsActionCreators, dispatch),
21+
monitorActions: bindActionCreatorsRecursively(actionCreators, dispatch)
22+
};
23+
}
24+
25+
const Monitor = connect(mapStateToProps, mapDispatchToProps)(component);
26+
Monitor.reducer = reducer;
27+
return Monitor;
28+
}

src/createDevTools.js

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
1-
import React, { cloneElement, Component, PropTypes } from 'react';
1+
import React, { Component, PropTypes } from 'react';
22
import enhance from './enhance';
3+
import connectMonitor from './connectMonitor';
4+
5+
export default function createDevTools(monitor) {
6+
const Monitor = connectMonitor(monitor);
37

4-
export default function createDevTools(Monitor) {
58
return class DevTools extends Component {
69
static contextTypes = {
710
store: PropTypes.object.isRequired
@@ -10,8 +13,11 @@ export default function createDevTools(Monitor) {
1013
static enhance = enhance(Monitor.reducer);
1114

1215
render() {
13-
return <Monitor store={this.context.store.devToolsStore} />;
16+
return (
17+
<Monitor {...this.props}
18+
store={this.context.store.devToolsStore} />
19+
);
1420
}
15-
}
21+
};
1622
}
1723

src/enhance.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { combineReducers, compose } from 'redux';
1+
import { combineReducers } from 'redux';
22

33
const ActionTypes = {
44
PERFORM_ACTION: 'PERFORM_ACTION',

0 commit comments

Comments
 (0)