useState
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.
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.
- If you pass a function as
Returns
useState
returns an array with exactly two values:
- The current state. During the first render, it will match the
initialState
you have passed. - 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.
- If you pass a function as
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 theset
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 anObject.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>
);
}
Call useState
and pass the initial state to it. React will store the state that you passed, and give it back to you.
To change the state, call the state setter function with the next state value. React will put that value into state instead.
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);
}
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.
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()
);
// ...
Most often, you will provide the initial state during render.
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:
- If the value you need can be computed entirely from the current props or other state, remove that redundant state altogether. If you’re worried about recomputing too often, the
useMemo
Hook can help. - If you want to reset the entire component tree’s state, pass a different
key
to your component. - If you can, update all the relevant state in the event handlers.
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.