Skip to content

Instantly share code, notes, and snippets.

@butchler
Last active September 5, 2016 14:15
Show Gist options
  • Save butchler/e0a6b47cb94126ab89352d9e04ad0e43 to your computer and use it in GitHub Desktop.
Save butchler/e0a6b47cb94126ab89352d9e04ad0e43 to your computer and use it in GitHub Desktop.
import { Children, createElement } from 'react';
export function replaceRenderedComponents(mappings) {
let componentMap;
if (mappings instanceof Map) {
componentMap = mappings
} else if (Array.isArray(mappings)) {
componentMap = new Map(mappings);
} else {
throw new Error('Expected Map or array of pairs');
}
const replace = getReplacer(componentMap);
return component => {
let wrapper;
if (component.prototype.isReactComponent) {
wrapper = class Wrapper extends component {
render() {
const output = super.render();
return replace(output);
}
};
} else if (typeof component === 'function') {
wrapper = (props) => {
const output = component(props);
return replace(output);
};
} else {
throw new Error('Expected React component');
}
wrapper.displayName = `replaceRenderedComponents(${component.displayName || component.name})`;
return wrapper;
};
}
function getReplacer(componentMap) {
const replace = element => {
if (!element) {
return null;
}
let type;
if (componentMap.has(element.type)) {
type = componentMap.get(element.type);
} else {
type = element.type;
}
const children = Children.map(element.children, replace);
return createElement(type, element.props, children);
};
return replace;
}
/**
* This is probably a bad idea, but it was interesting to write.
*
* Usage:
*
* ```
* import ParentComponent from 'components/parent';
* import ChildComponent from 'components/child';
* import ChildContainer from 'containers/child';
*
* const replace = replaceRenderedComponents([
* [ChildComponent, ChildContainer],
* ]);
*
* export default connect(mapState, mapDispatch)(replace(ParentComponent));
* ```
*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment