Reputation: 1188
I have a higher-order component that tracks the mouseover
event of any composed component. It is roughly like this:
(Component) => class TrackMouseOver extends React.Component {
handleMouseOver = (e) => {
console.log('Mouse over!');
};
render() {
return <Component {...this.props} onMouseOver={this.handleMouseOver}/>;
}
};
However, this does not work very well since React components do not bind to DOM event themselves. Unless the component handle the onMouseOver
prop, the HOC above won't work.
Without breaking the black-box nature of React components, is it better to always transfer props to child element? If yes, will there be significant performance impact by doing so?
Upvotes: 2
Views: 355
Reputation: 29999
If you start passing your handler function down, you will be going against the natural flow of events, as they bubble up through the DOM.
Instead, wrap your component in a handling element with a listener and make use of event bubbling.
(Component) => class TrackMouseOver extends React.Component {
handleMouseOver(e) {
e.target // is the element that triggered the event
e.currentTarget // is the element this handler is attached to
}
render() {
return (
<div onMouseOver={this.handleMouseOver}>
<Component {...this.props} />
</div>
);
}
};
When you click on one of the elements inside the new div
, the event has a two part lifecycle.
The browser works out which top level element the event happened to, then which child of that element and so on until the event finally ends up at an element with no children — the target.
This sequence won't trigger any event listeners (unless they have the useCapture
flag set), it just identifies the path of the event.
Now the event's target element has been reached, the event bubbles back up the captured path to the root of the DOM, triggering event listeners as it goes.
This is the reason that event handlers attached to the body
element always trigger*, regardless of which element the event happens to. The body
is a common ancestor for all elements.
In your case, you can utilise the fact that events for any elements inside your div
will eventually bubble their way up to this event handler.
You can work out which element the event came from using the event.target
.
* Event handlers won't trigger if an event handler on one of their descendant elements calls event.preventDefault
or event.stopPropagation
.
Upvotes: 2