The useEffect hook tribulations + Cheat Sheet
Tags: react, firebase, useeffect, cheatsheet
Published: 2020-10-06 12:54:16

Yesterday, while working on [this project](https://github.com/boostup/regalia-clothing/projects/1), I came to realise that logic contained in [`useFetchCollections`](https://github.com/boostup/regalia-clothing/blob/878d2be9f9f252d57db16f0131e48a2589131dab/src/contexts/collections/useFetchCollections.js) was flawed in that it was invoked endlessly.  

This had for perverse effect that the free daily allowed quota in `firestore` was reached !

**Read access to the cloud database was forbidden for almost 24 hours !!!!**

Therefore, to fix this, I pushed a commit that :

1) fixes the endless loop, and 
2) now makes use of `collections` data from a local json file instead of fetching it from the database (using `process.env.NODE_ENV` the code determines whether the environment is `production` or `development` in order to conditionally fetch this data set in one data source or the other)

## The `useEffect` hook tribulations

This loop happened because the data fetching was inside a `useEffect` hook, as seen [in this file history](https://github.com/boostup/regalia-clothing/blob/878d2be9f9f252d57db16f0131e48a2589131dab/src/contexts/collections/useFetchCollections.js): 

```
  const fetchCollections = fetchCollectionsAsync(setCollectionsState);

  useEffect(() => {
    fetchCollections();
  }, [fetchCollections]);
  return collectionsState;
};
``` 
The problem was to have included `fetchCollections` as a dependency inside the array (the second argument that `useEffect` takes).  Without its inclusion there, the **React** lib issued a warning :

``` 
React Hook useEffect has a missing dependency: `fetchCollections`.
Either include it or remove the dependency array. 
If `fetchCollections` changes too often, find the parent component that defines it and wrap that definition in useCallback
``` 

In this particular issue, I needed to ensure that `useEffect` fired only once, so the fix I issued is as follows:

```
  useEffect(() => {
    fetchCollectionsAsync(setCollectionsState);
  }, []);
```

The fix allowed to:

A) get rid of the **React** warning, and 
B) get `useEffect` to behave as needed by providing an empty dependency array, to have it fire **only once** in the whole component lifecycle.

### When NOT to pass array of dependency to `useEffect`

One of the suggestions found in the warning message was to `remove the dependency array`.  

After some research, it turns out that we must omit this array of dependency when we want `useEffect` to trigger:

- **everytime** the component it is in has finished rendering
- **whenever** `useEffect` is invoked

### Reminder about component rendering

A component will re-render when either: 

- props change
- state change
- the parent component re-renders

## `useEffect` Cheat Sheet
Even though Dan Abramov, the lead dev in the React team will not like it, here is a cheat sheet which "maps" `useEffect` use cases in terms of Class-based component lifecycles.

### ComponentDidMount
``` 
//Class
componentDidMount() {
    console.log('I just mounted!');
}

//Hooks
useEffect(() => {
    console.log('I just mounted!');
}, [])
``` 

### ComponentWillUnmount
``` 
//Class
componentWillUnmount() {
    console.log('I am unmounting');
}
 
//Hooks
useEffect(() => {
    return () => console.log('I am unmounting');
}, [])
``` 

### ComponentWillReceiveProps
``` 

//Class
componentWillReceiveProps(nextProps) {
    if (nextProps.count !== this.props.count) {
        console.log('count changed', nextProps.count);
    }
}
 
//Hooks
useEffect(() => {
    console.log('count changed', props.count);
}, [props.count])

```