React Pro Tip #1 — Name your `useEffect`!
Tags: react, beginners, cleancode, performance
Published: 2022-10-06 19:46:58

There's a very simple trick that will 10x your `useEffect` hooks' readability, and probably improve their performance, too: *use named functions as callbacks for your `useEffect`s*. You might even find that you don't need an effect at all!

---

Contents:
- [TLDR](#tldr)
- [Backstory](#backstory)
- [Drawbacks](#drawbacks)
- [Conclusion](#conclusion)
- [Further reading](#further-reading)

---

## TLDR
### Do this:
```typescript
useEffect(
  function doSomethingAfterMounting(){ // <--- name me!
    // Your effect code 
  },
  []
);
```

### Not this:
```typescript
useEffect( 
  () => {
    /**
    * Your effect code
    * 
    * Note that this may or may not make
	* sense to you in 6 months time.
	*/
  },
  []
);
```

### What for?

This should provide **3 key benefits**:

1. More *clarity in the purpose* of the effect, so other programmers would could easily tell what it's supposed to do just by reading the name;
2. If the effect throws an error, the *function's name will show up in the stack trace*, which should help debugging;
3. It should psychologically nudge the programmer into trying to *make the effect do only one thing*, and to split different tasks into several `useEffects` if necessary;

But before you even write a `useEffect`, [consider if you even need one](https://beta.reactjs.org/learn/you-might-not-need-an-effect)! There are plenty of situations where using `props` directly, or another hook like `useMemo` may make much more sense.

---

## Backstory
`useEffect` can be a dangerous hook if you don't know what you're doing. Doubly so because it's usually opaque, with little indication of intent. I can't count how many times I've stared at a giant `useEffect` with no idea what it was written to do, or what its authors were thinking.

Once upon a time, I had to refactor a huge amount of logic for a form page. The original author had used `useEffect` in [exactly the way that React doesn't recommend](https://beta.reactjs.org/learn/you-might-not-need-an-effect): 
- for updating state based on new props,
- for caching,
- for initializing field values,
- for fetching data from an API,

... and other bad practices.

Even worse, he had often written all of that functionality into *just one `useEffect`*. Clearly, someone had never heard of [`useMemo`](https://beta.reactjs.org/apis/react/useMemo) 😄 There were several `useEffects` that stretched to 50 lines or more. Worse yet, there were often several of them in one file, each of which had its own `setState` calls that made the effects dependent on each other. One file had 12 such `useEffects` (which, side note, is almost certainly far, far too much code for any single component!)

And alas, that was not the end of it. It turned out that these bad practices were littered throughout the website, on code written by several programmers over many months.

The refactoring took a week, and while it's nice to have some stable work to do, I'm pretty sure both I and the client would've preferred if I had been doing something more productive.

---

It was around that time that I realized that not only is `useEffect` very easy to abuse, but that probably the worst part of it was how opaque it was. I was reading Bob Martin's [Clean Code](https://www.goodreads.com/book/show/3735293-clean-code) around this time, and noticed that this gentleman had some pretty nice tips!

Among other pearls of wisdom, he advised that:
- all variables (and functions!) should have a clear, informative name:
- functions should be *small* and short, aim to *do one thing*, have *no side effects*, have minimal or *no repetition*, and should have *separated error handling*
- the best comment is *no comment at all* — your code should be *self-explanatory* in its intention through its concise logic and good naming

It was obvious to anyone with eyes that these principles were being woefully neglected in our client's codebase. So as I did my rewrites, I aimed to break up the enormous components with multiple `useEffect`s into smaller, easily understandable parts. One file could turn into two, or five, or even ten. This meant having to figure out what all of those giant effects actually did — and to do that, I often pulled out big chunks of logic into their own, shorter functions. `fetch()` effects got their own functions, as did `moveUI()`, `openModal()`, `reorderList()` and many others. It turned out that many of these things didn't even need to be effects, and were thus eliminated. 

But other things needed to stay as effects — things like `autoClose()` or `setHasMounted()`, and I wanted to find a way for these effect hooks to also have names. I aspired to code in a way so that even a person who didn't know how to program (or at least didn't know JavaScript) could see a name and instantly know the point of those few lines.

Comments wouldn't do, so I started out with the simple idea of using a memoized callback that would get automatically called whenever its dependencies changed:
```ts
// Idea #1: using a named `useCallback` to add clarity to `useEffect` (don't do this)

const doSomethingInAnEffect = useCallback(() => {
  // ... The effect code
}, [])

useEffect(() => doSomethingInAnEffect(), [doSomethingInAnEffect])
```
This definitely made things better. The effects finally had a meaning, even if they required this superfluous use of a memoized function.

It was at that point that one day it just struck me like a lightbulb: *if all I need is a name, why not just use an old-fashioned named function instead of an arrow function*? It seemed so simple, and why not? We never needed to use `this` inside the effect. And then we could avoid the new `useCallback`-hell that was festering. Could it really be so simple? I turned to Google, and as it turns out, I wasn't the first person with the idea (see the [sources](#further-reading) below). And if it's on Twitter, it must be a great idea, right? 😄

```ts
// Idea #2: just using an old-fashioned named function (DO do this)

useEffect(function doSomething() {
  // insert effect in here
}, []) // <-- notice: no extra dependencies! :) 
```

As I tried to name my effects, I realized that their names weren't always so obvious — and usually this was because one effect was trying to do too many things. Once I realized this, it became natural to split things apart until each effect did just "one thing" or just got removed completely, and our code quickly got more clearer and simpler as a result. Who knew that naming things well would turn out to be a gift that keeps on giving?

And so, since then, I've always used named functions whenever I needed `useEffect`, and I advise everyone else to do so, too.

---

I don't blame my colleagues (whom I also call my friends) for writing messy `useEffect`s. I've written plenty of unmaintainable code, too (haven't we all? 😄). Plus, back in those days, we didn't have awesome guidance articles like "[You Might Not Need an Effect](https://beta.reactjs.org/learn/you-might-not-need-an-effect)" (which I very much recommend you to read, by the way).

I'd also argue that we had inherited the psychological burden of only having one place for effects — namely, `componentDidUpdate` — from back in the days when we only had class components, and this may have nudged us into a "write a giant effect that handles everything"-state of mind that didn't always shake off naturally.

So what have we learned? I'd say that this experience taught me a few lessons:
- Make sure to *keep your functions as short as possible*. Ideally, they should do one thing.
	- This tip includes React components, too. If you need to render a giant form, it's probably better to split it up into different files for each section, and maybe even each field.
- `useEffect` shouldn't be treated as a "go to solution", and can be dangerous if you don't know what you're doing. To avoid hurting your app's performance, consider if you can get by with just using the `prop` itself, or with using `useMemo` and `useCallback`.
- And finally, while naming things may be one of [the only two hard things in computer science](https://www.karlton.org/2017/12/naming-things-hard/), it is absolutely vital for the readability of your code.
	- ...Which is why you absolutely *must* name all of your `useEffect`s with named functions! 😉

---

## Drawbacks
...Are there even any? 😄

So far, I haven't had any issues with this method, but have certainly felt the benefits.

One issue I can imagine occurring is pointer mismatches if you use the `this` keyword in your effect. Recall that [arrow functions do not have their own `this`, but rather use their parent's `this`](https://betterprogramming.pub/difference-between-regular-functions-and-arrow-functions-f65639aba256#:~:text=Regular%20functions%20created%20using%20function,be%20used%20as%20constructor%20functions.). That said, I have never, ever seen `this` being used in an effect, or in fact at all in a functional component... so I guess it's a non-issue? 😄

---

## Conclusion
From what I can see, we should all switch to using named functions in `useEffect`, and should do so immediately. This should make our code cleaner and more reliable, and doesn't seem to have any drawbacks. Not only would a simple name let everyone know your intentions, but it should push you to write short, "do only one thing" effects, too.

What do you think? Let me know in the comments! 🙂 And thanks for reading!

---
## Further reading:
- Sergio Xalambrí: [🔥 Pro Tip: Name your useEffect functions](https://sergiodxa.com/articles/pro-tip-name-your-useeffect-functions)
- Cory House: [Twitter thread about named `useEffect`s](https://twitter.com/housecor/status/1239622073909161986?lang=en)
- React documentation: [You Might Not Need an Effect](https://beta.reactjs.org/learn/you-might-not-need-an-effect)
- Robert C. Martin: [Clean Code: A Handbook of Agile Software Craftsmanship](https://www.goodreads.com/book/show/3735293-clean-code)
- Ashutosh Verma: [The Difference Between Regular Functions and Arrow Functions](https://betterprogramming.pub/difference-between-regular-functions-and-arrow-functions-f65639aba256#:~:text=Regular%20functions%20created%20using%20function,be%20used%20as%20constructor%20functions.)