When writing event handlers it’s common to adopt the handle{eventName} naming convention.
handleClick(e) { /* do something */ }
For components that handle several event types, these function names can be repetitive. The names themselves might not provide much value, as they simply proxy to other actions/functions.
handleClick() { require("./actions/doStuff")(/* action stuff */) }
handleMouseEnter() { this.setState({ hovered: true }) }
handleMouseLeave() { this.setState({ hovered: false }) }
Consider writing a single event handler for your component and switching on event.type.
handleEvent({type}) {
switch(type) {
case "click":
return require("./actions/doStuff")(/* action dates */)
case "mouseenter":
return this.setState({ hovered: true })
case "mouseleave":
return this.setState({ hovered: false })
default:
return console.warn(`No case for event type "${type}"`)
}
}
An alternative to the switch statement would be to use an event handlers hash map.
const handlers = {
click: () => require("./actions/doStuff")(/* action dates */),
mouseenter: () => this.setState({ hovered: true }),
mouseleave: () => this.setState({ hovered: false }),
default: () => console.warn(`No case for event type "${type}"`)
};
You would then have your handleEvent
function check if the event type has a corresponding handler,
in the handlers object, otherwise use the default
case.
This way, you don't have to modify handleEvent
each time you need to handle a new event.
handleEvent({type}) {
// Avoid mouseEnter, MouseLeave, Click
const NORMALIZED_TYPE = type.toLowerCase();
// If we have no registered handlers, we always use the 'default'
const HANDLER_TO_CALL = NORMALIZED_TYPE in handlers ? NORMALIZED_TYPE : 'default';
// No matter how many handlers we end up having in our `handlers` map, this code doesn't modify
handlers[HANDLER_TO_CALL].call(this);
}
You may also use try..catch
and avoid performing key lookups to validate handler presence
handleEvent({type}) {
try {
handlers[type.toLowerCase()].call(this);
} catch (e) {
handlers['default'].call(this);
}
}
Note that you have to bind your handler to the component — handler.bind(this)
— before calling it.
This makes sure that this
doesn't point to the handlers
object when one of the functions is invoked.
Alternatively, for simple components, you can call imported actions/functions directly from components, using arrow functions.
<div onClick={() => someImportedAction({ action: "DO_STUFF" })}
Don’t fret about performance optimizations until you have problems. Seriously don’t.