This question stems from my attempts to create a decorator-type component that adds functionality to dumb presentation components by wrapping them and injecting the desired styles and/or behavior.
Here is an example of a "hover decorator" I would like to create:
class HoverDecorator extends React.Component {
constructor(props) {
super(props);
let defaultState = { hover: false };
this.state = Object.assign(defaultState, props);
}
handleMouseOver(event) {
console.log('Mouse Over');
this.setState({
hover: true
});
}
handleMouseOut(event) {
console.log('Mouse Out');
this.setState({
hover: false
});
}
render() {
let hoverStyle = {};
if (this.state.hover) { // Change the color if hovered.
hoverStyle = { color: '#FF0000' };
}
// Inject the new style and event handlers into the child component.
return React.cloneElement(
React.Children.only(this.state.children), // Only allows a single child.
{
style: hoverStyle,
onMouseOver: this.handleMouseOver.bind(this),
onMouseOut: this.handleMouseOut.bind(this)
}
);
}
}
Which could be used on a dummy component like this:
class DummyTextBox extends React.Component {
constructor(props) {
super(props);
this.state = props;
}
render() {
let boxStyle = { color: '#0000FF' };
// Overwrite the default boxStyle with any styles passed in via props.
let mergedStyle = Object.assign(boxStyle, this.state.style);
return (<span style={mergedStyle}>{this.state.children}</span>);
}
}
The JSX used to create and wrap the DummyTextBox
would look like:
<HoverDecorator>
<DummyTextBox>Lorem Ipsum</DummyTextBox>
</HoverDecorator>
My problem is that the above code will add the onMouseOver
and onMouseOut
event listeners to the DummyTextBox
virtual DOM element, and not the actual span
that it renders. When I inspect the React DOM through the chrome extension, I see the following:
<HoverDecorator>
<DummyTextBox style={} onMouseOver=bound handleMouseOver() onMouseOut=bound handleMouseOut()>
<span style={color: "#0000FF"}>Lorem Ipsum</span>
</DummyTextBox>
</HoverDecorator>
This of course will not work, because DummyTextBox
is just a virtual DOM element by itself. Is there any way that I can add event listeners to the <span>
that is returned by the DummyTextBox
's render()
method?