I replaced useState hook with custom one
Tags: javascript, react, hooks, webdev
Published: 2020-04-12 12:23:50





---
title: I replaced useState hook with custom one
published: true
description: Repetition of defining useState hook for many different primitives were puzzling me for quite long time, until I came up with custom implementation of it.
tags: javascript, react, hooks, webdev
---
React hooks are already released since [React 16.8](https://github.com/facebook/react/blob/master/CHANGELOG.md#1680-february-6-2019). Most of developers fell in love with this "new" API but also small part of them still prefer to write components in good "old" class way.

I started to use this API almost from their release and I also would consider myself as a fan of hooks. So I'm on bright side, it means  that writing components without classes make the code very readable. It could also lead to less code, that means at the end of the day - **less bugs**. 

![Fast coding](https://media1.giphy.com/media/LmNwrBhejkK9EFP504/giphy.gif?cid=ecf05e4707229eed1480699993eec758567e84e86ffa9384&rid=giphy.gif)

React team has done great work and their [hooks API](https://reactjs.org/docs/hooks-reference.html) are covering every use case what developer may need when building beautiful React applications. However when building React applications with hooks I mostly use just basic hooks like: **useState**, **useEffect** and **useRef** and in more complex components also **useContext**, **useReducer** and **useMemo** come in handy. 

## Ok so get down to bussines and let's see some code 😍!

Initially, when I was using `useState` hook I found myself declaring many primitive state variables in single component. 

For simplicity let's consider example of controlled form with few inputs like this:
```javascript
function App() {
  const [name, setName] = useState("");
  const [email, setEmail] = useState("");
  const [phone, setPhone] = useState("");

  return (
    <form>
      <label>Name</label>
      <input type="text" value={name} onChange={e => setName(e.target.value)} />
      <label>Email</label>
      <input
        type="text"
        value={email}
        onChange={e => setEmail(e.target.value)}
      />
      <label>Phone</label>
      <input
        type="text"
        value={phone}
        onChange={e => setPhone(e.target.value)}
      />
    </form>
  );
}

export default App;
```
Form above is very simple example of basic hooks usage of state. Each field is stated in separate variable created by hook and this value is controlled by separate setter function. 

**OK but, what's wrong with it ?** 
I would say nothing :) Let's try to go back in time and have a look on the same component but in class approach like this:

```javascript
class App extends Component {
  state = {
    name: "",
    email: "",
    phone: ""
  };

  render() {
    return (
      <form>
        <label>Name</label>
        <input
          type="text"
          value={this.state.name}
          onChange={e => this.setState({ name: e.target.value })}
        />
        <label>Email</label>
        <input
          type="text"
          value={this.state.email}
          onChange={e => this.setState({ email: e.target.value })}
        />
        <label>Phone</label>
        <input
          type="text"
          value={this.state.phone}
          onChange={e => this.setState({ phone: e.target.value })}
        />
      </form>
    );
  }
}

export default App;
```
As you can see it's very similar and there is no special difference between them, just using `class` keyword and `render` method, right? But there is also one thing that for me was in this approach more convenient way of making components. 

Yes it's the **controlling** of the state by only one function `this.setState` and **accessing** the state by just one property `this.state`. This small little thing was great on class components and I missed this so much in functional world of React. 

**Are you asking why?**
Let's say you are coding component of which state is not very clear at the beginning and you are **adding, renaming or deleting** state properties on the go while coding.

For instance in the case of adding state properties I'd need to define new variables with their own names and setter functions. In `return` I'd need to access value and use separate setter for controlling state of hook. In case of definition of more state values it gives to component very fractional and repetition look, especially with `const` and `useState` keywords.

Diff of adding some new state values could look like this:
```diff
  const [name, setName] = useState("");
  const [email, setEmail] = useState("");
  const [phone, setPhone] = useState("");
+  const [address, setAddress] = useState("");
+  const [bio, setBio] = useState("");
```
If we consider this to be just the definition of component state with only five properties. In my opinion there is just a lot of repetition looking code, especially when comparing to class state definitions shown below.

```diff
  state = {
    name: "",
    email: "",
    phone: "",
+   address: "",
+   bio: "",
  };
```
In this case the state definition has clear and very understandable structure, without repetition code. Main game changer for me is that every state property can be accessed from one place and set by one function.
[Redux](https://redux.js.org/) guys may say it's like single source of truth for the one component. That's what I like about it. 

![enter image description here](https://media0.giphy.com/media/93d3nT74o6CgaoTSJ1/giphy.gif?cid=ecf05e47aa20f102c064bd28ea310bf2372758178157811a&rid=giphy.gif)
Declaring many variables and accessing them were puzzling me for quite long time until I came up with simple idea of custom hook called `useSetState`. 

**Take a glance on it in action bellow.**

```javascript
function App() {
  const [state, setState] = useSetState({
    name: "",
    email: "",
    phone: ""
  });
  
  return (
    <form>
      <label>Name</label>
      <input
        type="text"
        value={state.name}
        onChange={e => setState({ name: e.target.value })}
      />
      <label>Email</label>
      <input
        type="text"
        value={state.email}
        onChange={e => setState({ email: e.target.value })}
      />
      <label>Phone</label>
      <input
        type="text"
        value={state.phone}
        onChange={e => setState({ phone: e.target.value })}
      />
    </form>
  );
}

export default App;
```

**Wow 🤩! Just one hook for whole state? Controlled from one place?  Without using class ? That's pretty neat !**

Since the moment of definition this custom hook I just stopped using regular `useState` (I'm lying... I use it for super simple components f.e. togglers etc.) and I started to use it every time I need to store some state. 

This hook just brings to my code:
- less repetitive look
- better flexibility of accessing and controlling state
- easier handling of state changes 
- advantages of class state in functional component.


### Are you wondering how this custom hook looks like 🤔 ?
```javascript
const useSetState = (initialState = {}) => {
  const [state, regularSetState] = useState(initialState);

  const setState = newState => {
    regularSetState(prevState => ({
      ...prevState,
      ...newState
    }));
  };

  return [state, setState];
};
```


It's just simple custom hook with regular `useState` hook. The `useState` hook holds object by default. Then in defined `setState` function is calling regular setter function called `regularSetState`, **but instead of assigning primitive variables to state, its assigning merged object of previous state object and new state object**. This behavior leads to **opportunity to store many values in one state object  and to be set by one function**. So simple but so powerful.

![enter image description here](https://media0.giphy.com/media/x5kvlARMAkxri/giphy.gif?cid=ecf05e4792ee4ea45d42ad3f6f9e83428d84a303ba5fd4f5&rid=giphy.gif)





# Conclusion
For sure, I'm not the first who adjusted  `useState` hook like this. Maybe it's not even the right way to handle it, but it just works for me very well and i like it. Maybe it would work for you too.