Skip to content

The useState Hook

Let's start by looking at a common example, a minimal “counter” demo.

Click the button, and watch the count increase:

Code Playground

import React from 'react';

function Counter() {
const [count, setCount] = React.useState(0);

return (
<button onClick={() => setCount(count + 1)}>
Value: {count}
</button>
);
}

export default Counter;

There's a lot going on here, so let's break it down.

Our goal is to keep track of the number of times the user has clicked the button. Whenever we have “dynamic” values like this, we need to use React state. State is used for values that change over time.

To create a state variable, we use the useState function. This function takes a single argument: the initial value. In this case, that value initializes to 0. This value is chosen because when the page first loads, we've clicked the button 0 times.

useState is a hook. A hook is a special type of function that allows us to "hook into" React internals. We'll learn much more about hooks later in this course.

The useState hook returns an array containing two items:

  1. The current value of the state variable. We've decided to call it count.
  2. A function we can use to update the state variable. We named it setCount.

Naming conventions

When we create a state variable, we can name the two variables whatever we want. For example, this is equally valid:

const [hello, world] = React.useState(0);

That said, it's customary to follow the “x, setX” convention:

const [user, setUser] = React.useState();
const [errorMessage, setErrorMessage] = React.useState();
const [flowerBouquet, setFlowerBouquet] = React.useState();

The first destructured variable is the name of the thing we're tracking. The second variable prefixes that name with set, signifying that it's a function that can be called to change the thing. This is sometimes referred to as a “setter function”, since it sets the new value of the state variable.

Initial value

React state variables can be given an initial value:

const [count, setCount] = React.useState(1);
console.log(count); // 1

We can also supply a function. React will call this function on the very first render to calculate the initial value:

const [count, setCount] = React.useState(() => {
return 1 + 1;
});
console.log(count); // 2

This is sometimes called an initializer function. It can occasionally be useful if we need to do an expensive operation to calculate the initial value. For example, reading from Local Storage:

const [count, setCount] = React.useState(() => {
return window.localStorage.getItem('saved-count');
});

If you're not familiar with the Local Storage API, it's a way for us to save values on the user's device, so that it persists even after the browser tab is closed, and can be accessed on their next visit.

The benefit here is that we're only doing the expensive work (reading from Local Storage) once, on the initial render, rather than doing it on every single render.

We'll see a full example of how to persist React state to Local Storage later in the course.