Skip to content

Instantly share code, notes, and snippets.

@qwtel
Last active September 17, 2015 16:34
Show Gist options
  • Save qwtel/2b40d1a69932405d28aa to your computer and use it in GitHub Desktop.
Save qwtel/2b40d1a69932405d28aa to your computer and use it in GitHub Desktop.
Enhanced version of redux' connect, that puts all action creators into the child context of the component.
import {PropTypes} from 'react';
import {connect} from 'react-redux';
/**
* Enhanced version of redux' connect, that puts all action creators
* into the child context of the component.
*
* @param mapStateToProps {Function}
* @param mapDispatchToProps {Function} Must be free of side effects!
* @returns {Function}
*/
export default function connectContext(mapStateToProps, mapDispatchToProps) {
const childContextTypes = getChildContextTypes(mapDispatchToProps);
const wrappedMapDispatchToProps = wrapDispatchToProps(mapDispatchToProps);
return component => {
overwriteChildContextTypes(component, childContextTypes);
overwriteGetChildContext(component);
return connect(mapStateToProps, wrappedMapDispatchToProps)(component);
};
}
function getChildContextTypes(mapDispatchToProps) {
const childContextTypes = {};
// Just interested in the keys.
// Hopefully your `mapDispatchToProps` implementation doesn't have side effects...
Object.keys(mapDispatchToProps(() => {}))
.forEach(key => {
// TODO: allow objectOf(func)
childContextTypes[key] = PropTypes.func;
});
return childContextTypes;
}
function wrapDispatchToProps(mapDispatchToProps) {
return dispatch => {
const actionCreators = mapDispatchToProps(dispatch);
return {
actionCreators,
...actionCreators, // also include them in props, like a normal `connect` would do
};
}
}
function overwriteChildContextTypes(component, childContextTypes) {
Object.assign(component.childContextTypes, childContextTypes);
}
function overwriteGetChildContext(component) {
const originalGetChildContext = component.prototype.getChildContext;
// using `function` so that `this` points to the actual instance of the component.
component.prototype.getChildContext = function () {
// get the original child context and assign all the `actionCreators` we "saved" in `props` on to it.
return Object.assign(originalGetChildContext.call(this), this.props.actionCreators);
};
}
import React, {Component, PropTypes} from 'react';
import {bindActionCreators} from 'redux';
import connectContext from './connectContext';
function click() {
return {
type: 'CLICK',
}
}
function mapStateToProps(state) {
return state;
}
function mapDispatchToProps(dispatch) {
return bindActionCreators({click}, dispatch);
}
@connectContext(mapStateToProps, mapDispatchToProps)
class Parent extends Component {
render() {
return <Child />;
}
}
class Child extends Component {
contextTypes: {
click: PropTypes.func,
}
render() {
<button onClick={this.context.click}/>
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment