A guide to useState in React
Tags: frontenddev, react, javascript
Published: 2019-07-08 19:11:13

---
title: A guide to useState in React
published: true
tags: front-end-developmen,react,javascript
canonical_url: https://blog.logrocket.com/a-guide-to-usestate-in-react-ecb9952e406c
---

![](https://cdn-images-1.medium.com/max/792/1*maE0ve6HItzdk7hdkdApMQ.png)

useState is a hook that allows you to have state variables in functional components.

There are two types of components in React, class and functional components.

**Class components** are [ES6 classes](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Classes) that extend from [React.Component](https://reactjs.org/docs/react-component.html) and can have [state and lifecycle methods](https://reactjs.org/docs/state-and-lifecycle.html):
```jsx
class Message extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      message: ‘’    
    };
  }

  componentDidMount() {
    /* ... */
  }

  render() {
    return <div>{this.state.message}</div>;
  }
}
```
**Functional components** are functions that just accept arguments as the properties of the component and return valid JSX:
```jsx
function Message(props) {
  return <div>{props.message}</div>
}
// Or as an arrow function
const Message = (props) =>  <div>{props.message}</div>
```
As you can see, there are no state or lifecycle methods.

However, since React 16.8 we can use **hooks,** which are functions with names starting with use, to add state variables to functional components and instrument the lifecycle methods of classes.

This article is a guide to the useSate (state) hook, the equivalent of this.state/this.setSate for functional components.

[![](https://cdn-images-1.medium.com/max/1024/1*GPjaPKNNUYHU8EsA3Z0JGA.png)](https://logrocket.com/signup/)

### Declaring state

useState is a named export from react so to use it, you can write:

```jsx
React.useState
```

Or to import it just write useState:

```jsx
import React, { useState } from 'react';
```

But unlike the state object that you can declare in a class, which allows you to declare more than one state variable, like this:
```jsx
import React from 'react';

class Message extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      message: '',
      list: [],    
    };
  }
  /* ... */
}
```
The useState hook allows you to declare only one state variable (of any type) at a time, like this:
```jsx
import React, { useState } from 'react';

const Message= () => {
   const messageState = useState( '' );
   const listState = useState( [] );
}
```
useState takes the initial value of the state variable as an argument. You can pass it directly, as shown in the previous example, or use a function to lazily initialize the variable (useful when the initial state is the result of an expensive computation):
```jsx
const Message= () => {
   const messageState = useState( () => expensiveComputation() );
   /* ... */
}
```
The initial value will be assigned only on the initial render (if it’s a function, it will be executed only on the initial render).

In subsequent renders (due to a change of state in the component or a parent component), the argument of the useState hook will be ignored and the current value will be retrieved.

It is important to keep this in mind because, for example, if you want to update the state based on the new properties the component receives:
```jsx
const Message= (props) => {
   const messageState = useState( props.message );
   /* ... */
}
```
Using useState alone won’t work because its argument is used the first time only, not every time the property changes (look [here](https://stackoverflow.com/questions/54625831/how-to-sync-props-to-state-using-react-hook-setstate) for the right way to do this).

But useState doesn’t return just a variable as the previous examples imply. It returns an array, where the first element is the state variable and the second element is a function to update the value of the variable:
```jsx
const Message= () => {
   const messageState = useState( '' );
   const message = messageState[0]; // Contains ''
   const setMessage = messageState[1]; // It’s a function
}
```
Usually, you’ll use [array destructuring](https://dev.to/sarah_chima/destructuring-assignment---arrays-16f) to simplify the code shown above:
```jsx
const Message= () => {
   const [message, setMessage]= useState( '' );
}
```
This way, you can use the state variable in the functional component like any other variable:
```jsx
const Message = () => {
  const [message, setMessage] = useState( '' );

  return (
    <p>
      <strong>{message}</strong>
    </p>
  );
};
```
But why does useState return array?

Because compared to an object, an array is more flexible and easy to use.

If the method returned an object with a fixed set of properties, you wouldn’t be able to assign custom names in an easy way. You’d have to do something like this (assuming the properties of the object are state and setState):
```jsx
// Without using object destructuring
const messageState = useState( '' );
const message = messageState.state;
const setMessage = messageState

// Using object destructuring
const { state: message, setState: setMessage } = useState( '' );
const { state: list, setState: setList } = useState( [] );
```
### Updating state

The second element returned by useState is a function that takes a new value to update the state variable.

Here’s an example that uses a text box to update the state variable on every change:
```jsx
const Message = () => {
  const [message, setMessage] = useState( '' );

  return (
    <div>
      <input
         type="text"
         value={message}
         placeholder="Enter a message"
         onChange={e => setMessage(e.target.value)}
       />
      <p>
        <strong>{message}</strong>
      </p>
    </div>
  );
};
```
Try it [here](https://codesandbox.io/s/7z31woqo9q).

However, this update function doesn’t update the value right away. Rather, it enqueues the update operation. Then, after re-rendering the component, the argument of useState will be ignored and this function will return the most recent value.

If you use the previous value to update state, you must pass a function that receives the previous value and returns the new value:
```jsx
const Message = () => {
  const [message, setMessage] = useState( '' );

  return (
    <div>
      <input
        type="text"
        value={message}
        placeholder="Enter some letters"
        onChange={e => {
          const val = e.target.value;
          setMessage(prev => prev + val)
        } }
      />
      <p>
        <strong>{message}</strong>
      </p>
    </div>
  );
};
```
Try it [here](https://codesandbox.io/s/v0n08rw547).

However, there are two important things to know about updates.

First, if you use the same value as the current state to update the state (React uses [Object.is](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is#Description) for comparing), React won’t trigger a re-render.

For example, when working with objects, it’s easy to make the following mistake:
```jsx
const Message = () => {
  const [messageObj, setMessage] = useState({ message: '' });

  return (
    <div>
      <input
        type="text"
        value={messageObj.message}
        placeholder="Enter a message"
        onChange={e => {
          messageObj.message = e.target.value;
          setMessage(messageObj); // Doesn't work
        }}
      />
      <p>
        <strong>{messageObj.message}</strong>
      </p>
  </div>
  );
};
```
Try it [here](https://codesandbox.io/s/50n0py0p6k).

Instead of creating a new object, the above example mutates the existing state object. To React, that’s the same object.

To make it work, a new object must be created:
```jsx
onChange={e => {
  const newMessageObj = { message: e.target.value };
  setMessage(newMessageObj); // Now it works
}}
```
This leads us to the second important thing you need to remember.

When you update a state variable, unlike this.setState in a component class, the function returned by useState does not automatically merge update objects, it replaces them.

Following the previous example, if we add another property to the message object (id):
```jsx
const Message = () => {
  const [messageObj, setMessage] = useState({ message: '', id: 1 });

  return (
    <div>
      <input
        type="text"
        value={messageObj.message}
        placeholder="Enter a message"
        onChange={e => {
          const newMessageObj = { message: e.target.value };
          setMessage(newMessageObj); // id property is lost
        }}
      />
      <p>
        <strong>{messageObj.id} : {messageObj.message}</strong>
      </p>
  </div>
  );
};
```
The new property is lost.

Try it [here](https://codesandbox.io/s/qqp8qp9zzq).

You can replicate this behavior by using the function argument and the object spread syntax:
```jsx
onChange={e => {
  const val = e.target.value;
  setMessage(prevState => {
    return { ...prevState, message: val }
  });
}}
```
This will have the same result as [Object.assign](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/assign), the ...prevState part will get all of the properties of the object and the message: val part will overwrite the message property.

For this reason, the React documentation recommends [splitting the state into multiple state variables based on which values tend to change together](https://reactjs.org/docs/hooks-faq.html#should-i-use-one-or-many-state-variables).

### Rules for using the state hook

useState follows the same [rules](https://reactjs.org/docs/hooks-rules.html) that all hooks do:

- Only call hooks at the top level
- Only call hooks from React functions

The second rule is easy to follow. Don’t use useState in a class component:
```jsx
class App extends React.Component {
  render() {
    const [message, setMessage] = useState( '' );

    return (
      <p>
        <strong>{message}</strong>
      </p>
    );
  }
}
```
Or regular JavaScript functions (not called inside a functional component):
```jsx
function getState() {
  const messageState = useState( '' );
  return messageState;
}
const [message, setMessage] = getState();
const Message = () => {
 /* ... */
}
```
You’ll get an [error](https://reactjs.org/warnings/invalid-hook-call-warning.html).

The first rule means that, even inside functional components, you shouldn’t call useState in loops, conditions, or nested functions because React relies on the order in which useState functions are called to get the correct value for a particular state variable.

In that regard, the most common mistake is to wrap useState calls or update function calls in a conditional statement (they won’t be executed all the time):
```jsx
const [message, setMessage] = useState( '' );
const [list, setList] = useState( [] );
if (condition) {
  setMessage( aMessage );  // Sometimes it will be executed, making the order change
}
setList( [1, 2, 3] );
```
A functional component can have many calls to useState or other hooks. Each hook is stored in a list, and there’s a variable that keeps track of the currently executed hook.

When useState is executed, the state of the current hook is read (or initialized during the first render), and then, the variable is changed to point to the next hook. That’s why it is important to always maintain the hook calls in the same order, otherwise, a value belonging to another state variable could be returned.

In general terms, here’s an example of how this works step by step:

1. React initializes the list of hooks and the variable that keeps track of the current hook
2. React calls your component for the first time
3. React finds a call to useState, creates a new hook object (with the initial state), changes the current hook variable to point to this object, adds the object to the hooks list, and return the array with the initial state and the function to update it
4. React finds another call to useState and repeats the actions of the previous step, storing a new hook object and changing the current hook variable
5. The component state changes
6. React sends the state update operation (performed by the function returned by useState) to a queue to be processed
7. React determines it needs to re-render the component
8. React resets the current hook variable and calls your component
9. React finds a call to useState, but this time, since there’s already a hook at the first position of the list of hooks, it just changes the current hook variable and returns the array with the current state and the function to update it
10. React finds another call to useState and since a hook exists in the second position, once again, it just changes the current hook variable and returns the array with the current state and the function to update it

If you like to read code, [ReactFiberHooks](https://github.com/facebook/react/blob/fd557d453d37eab29eca18f0507750ab2093669d/packages/react-reconciler/src/ReactFiberHooks.js) is the class where you can learn how hooks work under the hood.

### Conclusion

useState is a hook (function) that allows you to have state variables in functional components. You pass the initial state to this function, and it returns a variable with the current state value (not necessarily the initial state) and another function to update this value.

The important points to remember are:

- The update function doesn’t update the value right away
- If you use the previous value to update state, you must pass a function that receives the previous value and returns an updated value, for example, setMessage(previousVal => previousVal + currentVal)
- If you use the same value as the current state (React uses the[Object.is](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/is#Description) for comparing) to update the state, React won’t trigger a re-render
- Unlike this.setState in class components, useState doesn’t merge objects when the state is updated. It replaces them
- useState follows the same [rules](https://reactjs.org/docs/hooks-rules.html) that all hooks do. In particular, pay attention to the order in which these functions are called (there’s an [ESLint plugin](https://www.npmjs.com/package/eslint-plugin-react-hooks) that will help you enforce these rules)

For more advanced cases, you can use the [useReducer](https://reactjs.org/docs/hooks-reference.html#usereducer) hook.
* * *
### Plug: [LogRocket](https://logrocket.com/signup/), a DVR for web apps

[![](https://cdn-images-1.medium.com/max/1024/1*s_rMyo6NbrAsP-XtvBaXFg.png)](https://logrocket.com/signup/)<figcaption><a href="https://logrocket.com/signup/">https://logrocket.com/signup/</a></figcaption>

[LogRocket](https://logrocket.com/signup/) is a frontend logging tool that lets you replay problems as if they happened in your own browser. Instead of guessing why errors happen, or asking users for screenshots and log dumps, LogRocket lets you replay the session to quickly understand what went wrong. It works perfectly with any app, regardless of framework, and has plugins to log additional context from Redux, Vuex, and @ngrx/store.

In addition to logging Redux actions and state, LogRocket records console logs, JavaScript errors, stacktraces, network requests/responses with headers + bodies, browser metadata, and custom logs. It also instruments the DOM to record the HTML and CSS on the page, recreating pixel-perfect videos of even the most complex single-page apps.

[Try it for free](https://logrocket.com/signup/).
* * *
The post [A guide to useState in React](https://blog.logrocket.com/a-guide-to-usestate-in-react-ecb9952e406c/ appeared first on [LogRocket Blog](https://blog.logrocket.com).