We need to talk about state in React
Tags: react, webdev, javascript
Published: 2020-09-10 13:51:36

Everyone loves an opportunity to slam on the big dog of frontend - React; but when it comes to state, it really is first class!

Let's talk about state and explore how to make managing it a breeze.

## Literal forms of state

First off, it helps to understand the two forms that state can take in an application. 

### Explicit state

In the case of modern React, this is `useState` and `useReducer`. Explicit state doesn't just come out of thin air - it has to be _explicitly_ created and managed.

### Derived state

A psuedostate of sorts, derived state is a result of processing one or more states (explicit or derived).

```tsx
const [input, setInput] = useState(); // Explicit state
const inputValid = useMemo(           // Derived state
  () => input && input.length > 6,
  [input]
);
```

## Choosing types of state

Knowing whether to use explicit or derived state might seem challenging - but there's a really simple answer.

<br/>

> **Always use derived state where possible**

<br />

Forgetting to stick with the above rule can lead to redundant state. 

Unlike redundant code, redundant state is a real problem that actually exists; and can have an impact on everything from performance to maintainability.

### Spotting redundancy

If you've ever written something like the following - I know I have - you've probably been guilty of creating redundant state.

```tsx
const [value, setValue] = useState("");
const [isValid, setIsValid] = useState(false);

useEffect(
  () => setIsValid(value && value.length > 4), 
  [value]
);
```

A `useEffect` call which immediately calls a `setState` function is almost always an example of state that should be derived.

It doesn't seem like the worst thing in the world, and on it's own, it probably isn't. That being said, if this pattern  exists, there's a good chance it exists in many places and can lead to a larger problem.

### useEffect hell

Most of us have been on a project that has gone through _useEffect hell_. Trying to fix that one bug but being unable to trace it because a single state change causes a flurry of new renders.

The thing with `useEffect` is it can cause a cascading number of state updates... which in turn, can cause subsequent `useEffect` calls. This isn't an issue with the function itself - it's an issue with excessive state.

## Tips for managing state

If I had one piece of advice for managing state, it would be to keep it to a minimum... but I don't have one just one piece of advice - so here's some more!

### Batch state updates

When multiple state updates are being called at one time, it's useful to batch these together into one call.

##### With batching

```tsx
const [{ fetching, data }, setState] = useState({ 
  fetching: true, 
  data: undefined 
});

useEffect(() => {
  (async () => {
    const data = await getData();
    setState({ fetching: false, data })
  })()
}, []);

// State 1: { fetching: true, data: undefined }
// State 2: { fetching: false, data: 1234 }
```

##### Without batching

```tsx
const [fetching, setFetching] = useState(true);
const [data, setData] = useState();

useEffect(() => {  
  (async () => {
    const data = await getData();
    setFetching(false);
    setData(data);
  })()
}, []);

// State 1: { fetching: true, data: undefined }
// State 2: { fetching: false, data: undefined } 
// State 3: { fetching: false, data: 1234 }
```

Batched updates don't just mean fewer renders, there will be fewer possible states to deal with; making testing and reproductions much simpler.

> Remember, fewer renders means fewer state changes

### Use fixtures

Fixtures (or stories) are an incredible tool for understanding, modelling, and documenting all the states of your app. 

Find out more about fixtures [over here](https://dev.to/andyrichardsonn/fixture-first-development-14fk).

### Try useMemo more often

It's surprising [how much of an impact it can make](https://dev.to/andyrichardsonn/why-i-almost-always-usememo-and-usecallback-4776).

---

Hopefully, you found this interesting! If you have any thoughts or comments, feel free to drop them below or hit me up on twitter - @andyrichardsonn

Disclaimer: All thoughts and opinions expressed in this article are my own.