Ellie Strejlau


How Not to Code: React Edition

Over engineering and reinventing the wheel puts more burden on ourselves and our team to maintain code that we shouldn't need to.
696 words — Approx. 3 minutes
Photo by Levi Meir Clancy on Unsplash

The last time I had a blog, I started an entry series called “How Not to Write JavaScript”. At the time, I thought it would be useful to showcase how I have refactored code that I believed was over-engineered, poorly written, outdated, all of the above, etc. I realize that I might have been a little harsh in the way that I went about it, so I didn’t migrate those entries when I moved to this blog. However, I still see certain blocks of code that I would love to share how I would improve them. I don’t want to do so in an accusatory or shaming way; hopefully I can do so in a way that is informative. That way, if a person who writes something like this eventually sees this blog entry, they can learn something rather than feeling ashamed.

Code

const [ isHovered, setIsHovered ] = useState( false );
return (
  <div
    className={cls( styles.thing, { [styles.thingHover]: isHovered })}
    onClick={onClick}
    onMouseEnter={() => setIsHovered( true )}
    onMouseLeave={() => setIsHovered( false )}
  >
    {thing.text}
  </div>
);
React code that sets a classname on mouse hover and removes it when the mouse moves away from the object. This is eerily similar to another block of code I pointed out years ago, which was written in jQuery(!).

At first glance, you can say that this person understands React and the code looks consistent and clean. They also basically understand how to use event callbacks combined with basic React state management, JSX, CSS modules, and the classnames NPM package. However, it appears that this person didn’t fully understand the way that HTML and CSS natively work without frameworks or programming for accessibility. (Equal responsibility goes to whomever approved it in code review.)

Screenshot of a code editor outlining the accessibility issues that come from the original code. Errors read: "Visible, non-interactive elements with click handlers must have at least one keyboard listener. eslintjsx-a11y/click-events-have-key-events Static HTML elements with event handlers require a role. eslintjsx-a11y/no-static-element-interactions"

At least with our current linters at least we can catch these things more quickly?

I’ve seen a bunch of blocks like this in the wild in the last several years, including in an application that overrode basic link functionality for a web app by changing the window location manually. These are both excellent examples of over-engineering in front end development.

Objective

After reviewing the code in question, I went hunting to see if this code was being used to set any values elsewhere, and it wasn’t. It’s one thing if this also had to change a value or state somewhere else in the application, but all it was doing was changing styles on hover by adding or removing the thingHover class.

Resolution

I switched this out for a CSS :hover pseudo-class in order to make it simpler, and use more of what is available in the native browser and less JavaScript. Essentially:

<button onClick={clickHandler} className={styles.thing}>
  {thing.text}
</button>
.thing {
	/* Original styles */
}

.thing:hover {
	/* Hover styles */
}

If some other component in JavaScript or React needs to know when a user is hovering on this component (for whatever reason) and it doesn’t just change styles, then the onMouseEnter and onMouseLeave events are more useful. In this case, the former code block was unnecessarily rewriting the browser’s interpretation of a user hovering on an item and adding complexity to the existing codebase that we shouldn’t have to maintain. Choosing to roll your own version of any native browser functionality can be a recipe for disaster in the long run. Instead of relying on functionality maintained by browser developers and well-defined industry standards, the former might be completely ignored, break over time and cause accessibility issues. Changing an element or child element’s styles based on hover is something that should be done using the CSS :hover pseudo-class, which has been a staple of web development for the last several years, and is unlikely to change anytime soon.

© 2021 Ellie Strejlau. All rights reserved, except disclaimers (below) and quotes (cited).


This site was built with GatsbyJS. The social media icons were made by Pixel perfect. Most other icons made by Smashicons. Both can be found at Flaticon. Patterned backgrounds are from SVG Backgrounds.