Technical Failure #1: React hooks dependencies
Tags: react, javascript, leadership
Published: 2021-05-31 10:31:32

[React introduces hooks in 16.8](https://reactjs.org/blog/2019/02/06/react-v16.8.0.html) and everything changed. Hooks provided an opportunity to make functional components with state and lifecycles. The new approach required redefined mental models of how to write code in React. Not fully switching to a new approach lead to issues.

***

The work of a technical leader is full of decisions. You need to make them at the start and they can have an impact on the project even on the finish line. This series of article is for people who want to learn from my mistakes:

1. React hooks dependencies

***

### Situation

Let’s imagine we have a root component with a state that changes frequently and a component connected to the backend.

<script src="https://gist.github.com/Perfect7M/345ac41d2e24baec28b4ee93392cbe1b.js"></script>

This code update `Root` component state every 3s. Every time counter is incremented `ArticlesWithMutipleRerenders` component is re-rendered. This leads to the calling `getArticles` method every time the counter is changing.

### Why is this happen?

React uses reference equality when comparing dependencies to figure out it should run `useEffect` callback or not. In this case the following assign:

```js
const db = DBConnection();
```

every render `db` changes its reference, even if the value of this variable is the same as before.

That’s why `useEffect` callback runs every time component is rendered:

```js
useEffect(() => {
  console.count("get articles");
  db.getArticles().then(setArticles);
}, [db]);
```

### Bad decision

My decision seemed the easiest one and the simplest. When I was using `db` with `useEffect` or any hook, I just omitted this dependency. Code looked like this and everything was fine at the beginning:

```js
const db = DBConnection();
useEffect(() => {
  console.count("get articles");
  db.getArticles().then(setArticles);
}, []);
```

### The worst decision

One thing still bothered me. I got a warning from eslint that `db` dependency should be included in the dependency array.

![](https://cdn-images-1.medium.com/max/1600/1*JHzmWoNs_tXQXEyNdXS88A.png)Eslint rule warning

After the bad decision, there was an even worse one. I suppressed all of that in-place with `eslint-disable-next-line`. This led me to make it in every file multiple times and code loose much readability.

### The right way

Everything we need to do is memoize `db` and add it to the dependency array.

Why is this the best way?

* `DBConnection` can make multiple instances of the database connection. We want to keep as few connections as possible. That’s why we are creating one instance of the database connection.
* Passing `db` instance ensure that when instance changes we fetch articles again.

```js
const db = useMemo(() => DBConnection(), []);
useEffect(() => {
  console.count("get articles");
  db.getArticles().then(setArticles);
}, [db]);
```

### Conclusion

The right code you can check on [codesandbox](https://codesandbox.io/s/blue-shadow-72mhw?file=/src/App.js:556-690). Making mistakes is the way we learn. Development is making decisions and draws conclusions based on results.

Let me know in the comments below if you have any questions. [You can find me on Twitter.](https://twitter.com/Perfect7M)