When could (should) we merge two states?
Tags: react
Published: 2021-02-16 18:19:25

---
title: When could (should) we merge two states?
published: true
description: Managing multiple dependant states
tags: React
//cover_image: https://direct_url_to_image.jpg
---
If you look at the following gif when I tap on the likes button, you could see a jank where a `No likes found` screen is displayed, and then immediately `likes` are displayed.
 
 <img  src="https://media.giphy.com/media/tjMLQ1SDdjIGvdhkkN/giphy.gif">


I have seen this similar type of UX glitch in my project. The problem was with this piece of code.
```JSX
function LikesScreen() {
  const [isLoading, setIsLoading] = useState(true);
  const [likes, setLikes] = useState([]);
  useEffect(() =>  {
    setIsLoading(true);
    fetch("https://jsonplaceholder.typicode.com/todos/1").then((likes) => {
      setIsLoading(false);
      setLikes(likes);
    });
  }, []);

  if (isLoading) return <Loading />;
  if (likes.length === 0) {
    return <EmptyLikes />;
  }
  return <Likes likes={likes} />;
}
```

In the above code initially, the  `isLoading` state is true.
1. Loading screen is rendered.
2. Then the effect is triggered
3. A network request is made and the promise resolves with the `likes` data.


This is where the interesting thing happens. 

> React would **not batch state updates** triggered asynchronously i.e, in Promises, timeouts etc.  

So `setIsLoading(false)` would trigger a re-render and React would render `<EmptyLikes />`

Then `setLikes(likes)` would trigger another re-render and React would render `<Likes />`.

So the *setIsLoading ->Render -> setLikes-> Render* is the root cause of the issue.

# How can we fix this?
We can fix this by merging `isLoading` and `likes` states into a single state so that state updates are atomic.

```JSX
function LikesScreen() {
  const [{ isLoading, likes }, setState] = useState({
    isLoading: true,
    likes: []
  });
  useEffect(() => {
    setState((state) => {
      return { ...state, isLoading: true };
    });
    fetch("https://jsonplaceholder.typicode.com/todos/1").then((likes) => {
      setState({ likes, isLoading: false });
    });
  }, []);
  if (isLoading) return <Loading />;
  if (likes.length === 0) {
    return <EmptyLikes />;
  }
  return <Likes likes={likes} />;
}
```
> So when there are states which have the information about the same context then they could be merged so that the state updates become atomic.

This is a simple case but for complex cases, the state update logics might be more complex and would have been spread throughout the component.

In those cases, **useReducer** would be really helpful by colocating all of the state update logic.

## Next thing

Even after all of this, there could still be a problem.

Consider the state contains 5 boolean fields. Then the total possible states would be 2 pow  5 = 32.
 
> The component should handle all these possible 32 cases. Creating these type of components could be hard

So the solution is to make **Illegal states impossible to represent** about which I will be writing in the [next article](https://dev.to/acsreedharreddy/why-make-illegal-states-impossible-to-represent-1dkn)🤗