Connect once at the top

This commit is contained in:
Dan Abramov 2015-09-28 16:10:33 +03:00
parent 4375d69d5e
commit 2138ca663e
5 changed files with 83 additions and 40 deletions

View File

@ -4,8 +4,7 @@
import React, { Component, PropTypes } from 'react';
import Dock from 'react-dock';
import { connect } from 'react-redux';
import { combineReducers, bindActionCreators } from 'redux';
import { combineReducers } from 'redux';
const POSITIONS = ['left', 'top', 'right', 'bottom'];
@ -14,7 +13,7 @@ class DockMonitor extends Component {
monitorState: PropTypes.shape({
position: PropTypes.oneOf(POSITIONS).isRequired,
isVisible: PropTypes.bool.isRequired,
childState: PropTypes.any
child: PropTypes.any
}).isRequired,
monitorActions: PropTypes.shape({
@ -75,7 +74,7 @@ function changePosition() {
return { type: CHANGE_POSITION };
}
export default function create(ChildMonitor, {
export default function create(child, {
defaultIsVisible = true,
defaultPosition = 'right'
} = {}) {
@ -91,37 +90,27 @@ export default function create(ChildMonitor, {
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>
const ChildMonitor = child.component;
const CompositeMonitor = ({ monitorState, monitorActions, ...rest }) => (
<DockMonitor monitorState={monitorState}
monitorActions={monitorActions}>
<ChildMonitor {...rest}
monitorState={monitorState.child}
monitorActions={monitorActions.child} />
</DockMonitor>
);
CompositeMonitor.reducer = combineReducers({
childState: ChildMonitor.reducer,
return {
component: CompositeMonitor,
reducer: combineReducers({
position,
isVisible
});
return CompositeMonitor;
isVisible,
child: child.reducer
}),
actionCreators: {
toggleVisibility,
changePosition,
child: child.actionCreators
}
};
}

View File

@ -0,0 +1,20 @@
import { bindActionCreators } from 'redux';
export default function bindActionCreatorsRecursively(actionCreators, dispatch) {
return Object.keys(actionCreators).reduce((result, key) => {
if (!actionCreators[key]) {
return result;
}
switch (typeof actionCreators[key]) {
case 'object':
result[key] = bindActionCreatorsRecursively(actionCreators[key], dispatch);
break;
case 'function':
result[key] = bindActionCreators(actionCreators[key], dispatch);
break;
default:
break;
}
return result;
}, {});
}

28
src/connectMonitor.js Normal file
View File

@ -0,0 +1,28 @@
import { bindActionCreators } from 'redux';
import bindActionCreatorsRecursively from './bindActionCreatorsRecursively';
import { connect } from 'react-redux';
import { ActionCreators as devToolsActionCreators } from './enhance';
export default function connectMonitor({
component,
reducer = () => null,
actionCreators = {}
}) {
function mapStateToProps(state) {
return {
devToolsState: state.devToolsState,
monitorState: state.monitorState
};
}
function mapDispatchToProps(dispatch) {
return {
devToolsActions: bindActionCreators(devToolsActionCreators, dispatch),
monitorActions: bindActionCreatorsRecursively(actionCreators, dispatch)
};
}
const Monitor = connect(mapStateToProps, mapDispatchToProps)(component);
Monitor.reducer = reducer;
return Monitor;
}

View File

@ -1,7 +1,10 @@
import React, { cloneElement, Component, PropTypes } from 'react';
import React, { Component, PropTypes } from 'react';
import enhance from './enhance';
import connectMonitor from './connectMonitor';
export default function createDevTools(monitor) {
const Monitor = connectMonitor(monitor);
export default function createDevTools(Monitor) {
return class DevTools extends Component {
static contextTypes = {
store: PropTypes.object.isRequired
@ -10,8 +13,11 @@ export default function createDevTools(Monitor) {
static enhance = enhance(Monitor.reducer);
render() {
return <Monitor store={this.context.store.devToolsStore} />;
}
return (
<Monitor {...this.props}
store={this.context.store.devToolsStore} />
);
}
};
}

View File

@ -1,4 +1,4 @@
import { combineReducers, compose } from 'redux';
import { combineReducers } from 'redux';
const ActionTypes = {
PERFORM_ACTION: 'PERFORM_ACTION',