Event Delegator React Mixin
Oh man. At my job this past week I’ve been kind of a bad dev. I’ve just been like, “Screw it, this week is my week. No more CSS. I’m going to go make something super great.” Talk about famous last words. But I didn’t care! I was going to change the world around me for the better.
The Problem:
We needed a user experience where we wanted to create an environment where a click to an aimless place within it would have a certain affect on specific components. Applications for this kind of system include opening and closing drop downs, executing a single function of any kind when a user does this kind of behavior.
This is not something I can do with CSS alone. I was overjoyed. I heard the faint siren call of some passage in Douglas Crockford’s JavaScript: The Good Parts. It said, “Let’s do some event delegation!”.
What did I need to do to make my wildest dreams come true and do some good ‘ol JavaScript stuff?
At the highest level, I just needed to find a way to decide whether a user is trying to click a button or is just trying out that “click-out” behavior, which people default to when they navigate web sites. I’m a fan. I’m always doing that click-out behavior. I think that whoever first came up with this user experience is a genius. If a user feels frustrated while trying to navigate a user experience that is new to them, just randomly clicking can help them get where they want to go easily.
I first decided on a utility which literally saved references to different methods by caching them in easily accessible places and also stick event listeners on the document specified via an api. Then events caught in these listeners, which contain information identifying the element from where the event was triggered, were then used to execute the appropriate methods. Callback is a great way to describe how these methods were being treated. The event delegating part was JavaScript. The callbacks that they controlled would set state in some React components.
It worked! It was really complicated, though. I was also decentralizing my state by stuffing important pieces of it into something that was not a utility, it was a tumor popping off the side of this React component. Pure event delegation would never work well when dealing with the interplay of React’s event system and the actual DOM’s event system. You can’t have integral pieces of state circulating in different data flows. They will clash occasionally and ruin your life with annoying bugs. I’ve learned the hard way too many times. I swear this time I’m going to stop for real.
The second iteration was only slightly cooler. It let the React components, which housed the drop downs I wanted to toggle on “click out”, handle the user controlled actions. At the very least, that minimized the events running through the DOM, wreaking havoc and ruining lives. My life became a lot better. The code became a lot simpler. There were plenty of cons though. I had to devise a way of making clicks inside of the “click out”-able components not shut their parents. I resorted to created a white list of sorts, which was fine.
Event Delegator Mixin
After much code review, the last iteration was very much all hands inside the vehicle that is React. I did some awesome playing around with the React children prop and passing props into the children. It was a blast! It was just a sly React component, which in its application would wrap another component and give it event handling super powers. The top level listener was stuck in its render method and it held some stateful arrays of wrapped callbacks that would or wouldn’t trigger a behavior in a drop down or highlight a div (all of my use cases).
It worked perfectly! It was solid, too! I was simply amazed with my personal genius. The idea was simple and I was victorious. I had made it to the top of my own inner mountain. I got to do literally all the things! I’ll include a reproduction of it at some future date. I’m honestly a little disappointed that I didn’t think to make it that way in the first place. In the past I have stupidly tried to merge two different event driven systems. It caused unnecessary and random bugs. And everyone knows that it’s those random bugs that will be there where you application dies an early death. Don’t do it. You’ve been warned.
Sadly, the wonderful extra React stuff (the use of children props, passing props from parent to children, component composition in order to make super components…) was seen as unnecessary fluff. I was also told that stashing that much state in a different place than all the other state was a bad idea. I can agree with that. As someone who works on an app that once felt absolutely bottomless to me (aka all I do is poke at legacy code), the less surprises you introduce into the code base, the longer a life your code has.
It was super fun to make to make though. I think that the way the mixin was built, it may have been stable. No matter what though, I had to whitelist class names. I don’t really know what else to do though to help an event delegator distinguish between events that were issued by random vs intentional clicks without using the listener.