useState is a React Hook that lets you add a state variable to your component.

On this page

Reference

useState(initialState)

Call useState at the top level of your component to declare a state variable.

import { useState } from 'react';

function MyComponent() {
  const [age, setAge] = useState(28);
  const [name, setName] = useState('Taylor');
  const [todos, setTodos] = useState(() => createTodos());
  // ...

The convention is to name state variables like [something, setSomething] using array destructuring.

See more examples below.

Parameters

  • initialState: The value you want the state to be initially. It can be a value of any type, but there is a special behavior for functions. This argument is ignored after the initial render.
    • If you pass a function as initialState, it will be treated as an initializer function. It should be pure, should take no arguments, and should return a value of any type. React will call your initializer function when initializing the component, and store its return value as the initial state. See an example below.

Returns

useState returns an array with exactly two values:

  1. The current state. During the first render, it will match the initialState you have passed.
  2. The set function that lets you update the state to a different value and trigger a re-render.

Caveats

  • useState is a Hook, so you can only call it at the top level of your component or your own Hooks. You can’t call it inside loops or conditions. If you need that, extract a new component and move the state there.
  • In Strict Mode, React will call your initializer function twice in order to help you find accidental impurities. This is development-only behavior and does not affect production. If your initializer function is pure (as it should be), this should not affect the logic of your component. The result from one of the calls will be ignored.

set functions, like setSomething(nextState)

The set function returned by useState lets you update the state to a different value and trigger a re-render. You can pass the next state directly, or a function that calculates it from the previous state:

const [name, setName] = useState('Edward');

function handleClick() {
  setName('Taylor');
  setAge(a => a + 1);
  // ...

Parameters

  • nextState: The value that you want the state to be. It can be a value of any type, but there is a special behavior for functions.
    • If you pass a function as nextState, it will be treated as an updater function. It must be pure, should take the pending state as its only argument, and should return the next state. React will put your updater function in a queue and re-render your component. During the next render, React will calculate the next state by applying all of the queued updaters to the previous state. See an example below.

Returns

set functions do not have a return value.

Caveats

  • The set function only updates the state variable for the next render. If you read the state variable after calling the set function, you will still get the value that was on the screen before your call.

  • If the new value you provide is identical to the current state, as determined by an Object.is comparison, React will bail out of re-rendering the component and its children. However, in some cases React may still need to call your component before discarding the result.

  • Calling the set function during rendering is only allowed from within the currently rendering component. React will discard its output and immediately attempt to render it again with the new state. React will do this in a loop until you either stop setting state, or do it too many times. This pattern is called “derived state”. It is uncommon, but you can use it to store information from previous renders. See an example below.

  • In Strict Mode, React will call your updater function twice in order to help you find accidental impurities. This is development-only behavior and does not affect production. If your updater function is pure (as it should be), this should not affect the logic of your component. The result from one of the calls will be ignored.


Usage

Adding state to a component

First, declare the state variables you need. Then, update them on interaction and display them in your JSX.

import { useState } from 'react';

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

  function handleClick() {
    setCount(count + 1);
  }

  return (
    <button onClick={handleClick}>
      You pressed me {count} times
    </button>
  );
}
1
Declare a state variable

Call useState and pass the initial state to it. React will store the state that you passed, and give it back to you.

2
Set state on interaction

To change the state, call the state setter function with the next state value. React will put that value into state instead.

3
Render state in the UI

Use the state in your JSX or component logic.

Basic useState examples

Example 1 of 4:
Counter (number)

In this example, the count state variable holds a number. Clicking the button increments it.

import { useState } from 'react';

export default function Counter() {
  const [count, setCount] = useState(0);

  function handleClick() {
    setCount(count + 1);
  }

  return (
    <button onClick={handleClick}>
      You pressed me {count} times
    </button>
  );
}

Read state as a component’s memory to learn more.


Updating state based on the previous state

This code looks like it increments the counter three times, but it only increments once:

const [count, setCount] = useState(0);

function handleClick() {
  setCount(count + 1); // setCount(0 + 1)
  setCount(count + 1); // setCount(0 + 1)
  setCount(count + 1); // setCount(0 + 1)
}

This is because calling setCount will not update the count until the next render, so each call becomes setCount(0 + 1). To make a series of state changes, each of which depends on the previous state, pass an updater function to setCount. React will queue them and run them all to calculate state on next render.

function handleClick() {
  // 0 => 1
  setCount(c => c + 1);

  // 1 => 2
  setCount(c => c + 1);

  // 2 => 3
  setCount(c => c + 1);
}
1
You receive: Pending state

You get the latest state with the previously queued updates applied to it. For example, if count was 0 and you call setCount(c => c + 1) three times in a row, then the pending c state will be 0 in the first updater, 1 in the second one, and 2 in the third one, and 3 is the final state.

2
You return: Next state

You return the next state you want to see on the screen.

import { useState } from 'react';

export default function Counter() {
  const [count, setCount] = useState(0);

  function handleClick() {
    setCount(c => c + 1);
    setCount(c => c + 1);
    setCount(c => c + 1);
    console.log(count); // Still 0 until next render!
  }

  return (
    <>
      <h1>{count}</h1>
      <button onClick={handleClick}>+3</button>
    </>
  );
}

Read state as a snapshot and queueing a series of state changes to learn more.

Note

Updaters need to be pure functions that only calculate and return the next state. Don’t “do” things or set state from the updater functions. React runs updater functions twice in development only in Strict Mode to stress-test them. This shouldn’t affect pure functions, so it helps find accidental impurities.

Deep Dive

Is using an updater always preferred?


Updating objects and arrays in state

You can put objects and arrays into state. In React, state is considered read-only, so you should replace it rather than mutate your existing objects. For example, if you have a form object in state, don’t update it like this:

// Don't mutate an object in state like this:
form.firstName = 'Taylor';

Instead, replace the whole object by creating a new one:

setForm({
  ...form,
  firstName: 'Taylor'
});

Examples of objects and arrays in state

Example 1 of 4:
Form (object)

In this example, the form state variable holds an object. Each input has a change handler that calls setForm with the next state of the entire form. The { ...form } spread syntax ensures that the state object is replaced rather than mutated.

import { useState } from 'react';

export default function Form() {
  const [form, setForm] = useState({
    firstName: 'Barbara',
    lastName: 'Hepworth',
    email: 'bhepworth@sculpture.com',
  });

  return (
    <>
      <label>
        First name:
        <input
          value={form.firstName}
          onChange={e => {
            setForm({
              ...form,
              firstName: e.target.value
            });
          }}
        />
      </label>
      <label>
        Last name:
        <input
          value={form.lastName}
          onChange={e => {
            setForm({
              ...form,
              lastName: e.target.value
            });
          }}
        />
      </label>
      <label>
        Email:
        <input
          value={form.email}
          onChange={e => {
            setForm({
              ...form,
              email: e.target.value
            });
          }}
        />
      </label>
      <p>
        {form.firstName}{' '}
        {form.lastName}{' '}
        ({form.email})
      </p>
    </>
  );
}

Read updating objects in state and updating arrays in state to learn more.


Avoiding recreating the initial state

The initial state that you pass to useState is only used for the initial render. For the next renders, this argument is ignored. If creating the initial state is expensive, it is wasteful to create and throw it away on every render. To avoid this, you can pass an initializer function to useState. React will only run it during the initialization to calculate the initial state, but won’t run it for re-renders. This is a performance optimization.

function TodoList() {
  const [text, setText] = useState('');

  const [todos, setTodos] = useState(
    () => createInitialTodos()
  );

  // ...
1
Initializing state with a value

Most often, you will provide the initial state during render.

2
Initializing state with a function

But you can also give React a function that calculates the initial state instead. React will only call that function when initializing the component, and won’t call it again.

import { useState } from 'react';

function createInitialTodos() {
  const initialTodos = [];
  for (let i = 0; i < 50; i++) {
    initialTodos.push({
      id: i,
      text: 'Item #' + i
    });
  }
  return initialTodos;
}

export default function TodoList() {
  const [todos, setTodos] = useState(createInitialTodos);

  return (
    <ul>
      {todos.map(item => (
        <li key={item.id}>
          {item.text}
        </li>
      ))}
    </ul>
  );
}

Note

Initializers need to be pure functions that only calculate and return the initial state. Don’t “do” things or set state from the initializer functions. React runs initializer functions twice in development only in Strict Mode to stress-test them. This shouldn’t affect pure functions, so it helps find accidental impurities.


Resetting state with a key

Typically, you might encounter the key attribute when rendering lists. However, it also serves another purpose.

You can reset a component’s state by passing a different key to a component. In this example, the Reset button changes the version state variable, which we pass as a key to the Form. When the key changes, React re-creates the Form component (and all of its children) from scratch, so its state gets reset.

Read preserving and resetting state to learn more.

import { useState } from 'react';

export default function App() {
  const [version, setVersion] = useState(0);

  function handleReset() {
    setVersion(version + 1);
  }

  return (
    <>
      <button onClick={handleReset}>Reset</button>
      <Form key={version} />
    </>
  );
}

function Form() {
  const [name, setName] = useState('Taylor');

  return (
    <>
      <input
        value={name}
        onChange={e => setName(e.target.value)}
      />
      <p>Hello, {name}.</p>
    </>
  );
}

Storing information from previous renders

Usually, you will update state in event handlers. However, in rare cases you might want to adjust state in response to rendering — for example, you might want to change a state variable when a prop changes.

In most cases, you don’t need this:

In the rare case that none of these apply, there is a pattern you can use to update state based on the values that have been rendered so far, by calling a set function while your component is rendering.

Here’s an example. This CountLabel component displays the count prop passed to it:

export default function CountLabel({ count }) {
  return <h1>{count}</h1>
}

Say you want to show whether the counter has increased or decreased since the last change. The count prop doesn’t tell you this — you need to keep track of its previous value. Add the prevCount state variable to track it. Add another state variable called trend to hold whether the count has increased or decreased. Compare prevCount with count, and if they’re not equal, update both prevCount and trend. Now you can show both the current count prop and how it has changed since the last render.

import { useState } from 'react';

export default function CountLabel({ count }) {
  const [prevCount, setPrevCount] = useState(count);
  const [trend, setTrend] = useState(null);
  if (prevCount !== count) {
    setPrevCount(count);
    setTrend(count > prevCount ? 'increasing' : 'decreasing');
  }
  return (
    <>
      <h1>{count}</h1>
      {trend && <p>The count is {trend}</p>}
    </>
  );
}

Note that if you call a set function while rendering, it must be inside a condition like prevCount !== count, and there must be a call like setPrevCount(count) inside of the condition. Otherwise, your component would re-render in a loop until it crashes. Also, you can only update the state of the currently rendering component like this. Calling the set function of another component during rendering is an error. Finally, your set call should still update state without mutation — this special case doesn’t mean you can break other rules of pure functions.

This pattern can be hard to understand and is usually best avoided. However, it’s better than updating state in an effect. When you call the set function during render, React will re-render that component immediately after your component exits with a return statement, and before rendering the children. This way, children don’t need to render twice. The rest of your component function will still execute (and the result will be thrown away), but if your condition is below all the calls to Hooks, you may add return null inside it to restart rendering earlier.


Troubleshooting

I’ve updated the state, but logging gives me the old value

Calling the set function does not change state in the running code:

function handleClick() {
  console.log(count);  // 0

  setCount(count + 1); // Request a re-render with 1
  console.log(count);  // Still 0!

  setTimeout(() => {
    console.log(count); // Also 0!
  }, 5000);
}

This is because states behaves like a snapshot. Updating state requests another render with the new state value, but does not affect the count JavaScript variable in your already running event handler.

If you need to use the next state, you can save it in a variable before passing it to the set function:

const nextCount = count + 1;
setCount(nextCount);

console.log(count);     // 0
console.log(nextCount); // 1

I’ve updated the state, but the screen doesn’t update

React will ignore your update if the next state is equal to the previous state, as determined by an Object.is comparison. This usually happens when you change an object or an array in state directly:

obj.x = 10;
setObj(obj); // Doesn't do anything

You called setObj with the same obj object, so React bailed out of rendering. To fix this, you need to ensure that you’re always replacing objects and arrays in state instead of mutating them:

setObj({
  ...obj,
  x: 10
});

I’m getting an error: “Too many re-renders”

You might get an error that says: Too many re-renders. React limits the number of renders to prevent an infinite loop. Typically, this means that you’re unconditionally setting state during render, so your component enters a loop: render, set state (which causes a render), render, set state (which causes a render), and so on. Very often, this is caused by a mistake in specifying an event handler:

// 🚩 Wrong: calls the handler during render
return <button onClick={handleClick()}>Click me</button>

// ✅ Correct: passes down the event handler
return <button onClick={handleClick}>Click me</button>

// ✅ Correct: passes down an inline function
return <button onClick={(e) => handleClick(e)}>Click me</button>

If you can’t find the cause of this error, click on the arrow next to the error in the console, and look through the JavaScript stack to find the specific set function call responsible for the error.