React Hooks: A Super Serious Take

By Eric Turner

“What are React ‘hooks’, and should I be anxiously concerned about their existence?”

This is the question I asked myself when the rumblings began several years prior. “React hooks are cool”, I would overhear my peers say. Naturally, the mind begins to run wild with ideas, trying to imagine what these “hooks” could be and if they were possibly fishing, pirate or grappling related, and if there would be fun, light-hearted syntax to accompany these thematic new features. As I would soon discover, the answer is no. I wasn’t even close, and it was a really bad guess.

But what I did eventually find is a new syntax, mildly engaging but without a whimsical theme, that would allow me to write code in a leaner, concise, easy-to-reason-about way. It also let me avoid awkward run-ins with classes (we’ve been going through a separation) and parse out logic from lifecycles so that not ALL the things have to happen when my state updates. Furthermore, I found that using custom hooks, I could share logic between components without the software equivalent of a Rube Goldberg machine.

In this article, I want to share the initial concepts I found in React hooks, so let’s explore the basics — together, for safety and accountability!

The Basics

We start with the important question: Do I need to use hooks in React code? The answer is no, you don’t. But you probably could, should, and you might even *like* it. Some good news is that you can start using them in tandem with existing code, like two syntaxes riding the same React bicycle and pedaling in harmony. This negates the need to immediately refactor everything to include them, and often only slight refactoring is needed. Simply put, both are acceptable to use in the same code base (for now, as the official docs ominously warn), but you can’t use a hook inside a class.

And what is it, would one say, that hooks ‘do’, exactly? Well, they allow you to ‘hook’ into the React state and lifecycle stuff, thus the name. It’s horribly on the nose and disappointing, I know, but “devs gonna dev” when it comes to naming things. They hook (ugh) into those features in a functional way, as we’ll explore briefly.

To do just that, we are provided a whopping, nearly overwhelming, two built-in hooks.

The State Hook

In this example, we’ve tapped a bit into the state of our component, utilizing the useState hook to create a stateful property and a virtual burrito to keep ourselves motivated. For our efforts, we receive an array that we’re de-structuring into two items, the burrito property itself, which we can use in our templates and such, and a method to set the value of the burrito, setBurrito. We’ve also given the burrito an initial value, that of ‘Spicy Steak’. Later, we could update our burrito, using setBurrito’, to a more palatable ‘Avocado Chicken’.

Now, if you’ve used React previously, you might be thinking to yourself, “Hey! I’m supposed to set state in the constructor in the component class declaration!” You might also be thinking about how you could go for a burrito, but that’s for another tutorial on Pavlovian behavior and not really applicable here. Try to focus.

Well, you’re not wrong about the state stuff. But to reiterate, this can be used in place of having to extend a class, create a constructor and declare state inside said constructor. Both syntaxes can be used, just not in the same component. In fact, if you have an existing stateless component and find yourself needing to suddenly and desperately add stateful properties to such, the useState hook can be a great way to do so without needing to refactor and add a class.

The Effect Hook

If you’re like me, the security of my burrito often keeps me under high stress. What if someone were to tamper with the contents? How can I be confident I’m not about to bite into a burrito hiding a couple of low-end hot dogs and some novelty mayonnaise? I need to be notified, immediately and deafeningly, that a saboteur has fouled my fillings.

That means using the effect hook, which is fired off anytime state changes or the component reaches a lifecycle phase. The official documentation says, “When you call useEffect, you’re telling React to run your ‘effect’ function after flushing changes to the DOM.” This is a statement full of poor imagery but does indicate any DOM change, including those that normally occur at lifecycle phases like componentDidMount, will run the given function.

Does this mean that every time any change to the DOM occurs, the effect function will run? Yes, it does, and much like next-gen console scalpers, that’s not usually helpful and mostly infuriatingly detrimental and also I don’t like it at all. However, what if we could have some simple control that enables us to specify exactly when it should run and only then?

We can pass a second argument, [burrito], that tells useEffect to run ONLY if the burrito itself is updated. I don’t care if they tussle my taco, chuff my chimichanga or eff with my enchilada, but you bust open my burrito and I want the alarm sounded. Also, why are Tex-Mex saboteurs so into alliteration? Regardless, this means that only if the burrito is built, bothered, or binned (mounted, updated, or destroyed) will the effect be run, so if you absolutely must update the state of another property within an effect, this is a great way to avoid the stack overflow of perpetual state updates. It’s also a fine choice for separating concerns as you can use as many effects as needed and place them where it makes sense in your code.

Creating New Hooks

While not going into full detail here, I do want to mention the creation of your own hooks and sharing stateful logic. Stateful logic is code that can be shared, but not state itself, between components, and is a great way to easily share functionality. What it’s not is what happens when you combine two states to form a logical portmanteau, such as Florida and Georgia to form Florgia which Wikipedia says is near Jacksonville.

An example might be fetching data from an API; you could abstract the logic necessary for getting a list of burritos from the burrito store API, and using the above native hooks useState and useEffect, store that list of burritos in state and perhaps fetch it when a new burrito notification is received. All of this, within one custom hook, can be imported and used concisely in all of the many components that need a fresh list of burritos without having to repeat code, because everyone loves a DRY burrito!

A Few Caveats

There are a few items worth mentioning, some stipulations that require attention, from the official documentation.

First, “Only call Hooks at the top level. Don’t call Hooks inside loops, conditions, or nested functions.” Seems simple and avoidable enough, but if you find yourself needing to commit those sins, grab a burrito of your own understanding and have a rethink about your code.

And second, “Only call Hooks from React function components. Don’t call Hooks from regular JavaScript functions.” Regular JavaScript functions never have any fun and this is no exception, you’ll need a magical React component or your own custom hook that gets imported into a React component. Not a huge deal but important to note.

Post-meal thoughts

That’s just the first bite of React hooks. With those simple ingredients, functional, clean code can be prepared alongside traditional, class-based React in a way and pace that makes sense to your codebase.

Final question: Have you ever made yourself hungry writing about code?