useState is a React Hook that lets you add astate variable to your component.
const[state,setState] =useState(initialState)Reference
useState(initialState)
CalluseState at the top level of your component to declare astate variable.
import{useState}from'react';
functionMyComponent(){
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] usingarray 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 aninitializer 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
initialStateyou have passed. - The
setfunction that lets you update the state to a different value and trigger a re-render.
Caveats
useStateis a Hook, so you can only call itat 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 into it.- In Strict Mode, React willcall your initializer function twice in order tohelp 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 behavior. The result from one of the calls will be ignored.
set functions, likesetSomething(nextState)
Theset function returned byuseState 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');
functionhandleClick(){
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 anupdater 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
setfunctiononly updates the state variable for thenext render. If you read the state variable after calling thesetfunction,you will still get the old 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.iscomparison, React willskip re-rendering the component and its children. This is an optimization. Although in some cases React may still need to call your component before skipping the children, it shouldn’t affect your code.Reactbatches state updates. It updates the screenafter all the event handlers have run and have called their
setfunctions. This prevents multiple re-renders during a single event. In the rare case that you need to force React to update the screen earlier, for example to access the DOM, you can useflushSync.The
setfunction has a stable identity, so you will often see it omitted from Effect dependencies, but including it will not cause the Effect to fire. If the linter lets you omit a dependency without errors, it is safe to do.Learn more about removing Effect dependencies.Calling the
setfunctionduring 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. This pattern is rarely needed, but you can use it tostore information from the previous renders.See an example below.In Strict Mode, React willcall your updater function twice in order tohelp 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 behavior. The result from one of the calls will be ignored.
Usage
Adding state to a component
CalluseState at the top level of your component to declare one or morestate variables.
import{useState}from'react';
functionMyComponent(){
const[age,setAge] =useState(42);
const[name,setName] =useState('Taylor');
// ...The convention is to name state variables like[something, setSomething] usingarray destructuring.
useState returns an array with exactly two items:
- Thecurrent state of this state variable, initially set to theinitial state you provided.
- The
setfunction that lets you change it to any other value in response to interaction.
To update what’s on the screen, call theset function with some next state:
functionhandleClick(){
setName('Robin');
}React will store the next state, render your component again with the new values, and update the UI.
Pitfall
Calling theset functiondoes not change the current state in the already executing code:
functionhandleClick(){
setName('Robin');
console.log(name);// Still "Taylor"!
}It only affects whatuseState will return starting from thenext render.
Example 1 of 4:Counter (number)
In this example, thecount state variable holds a number. Clicking the button increments it.
import{useState}from'react';exportdefaultfunctionCounter(){const[count,setCount] =useState(0);functionhandleClick(){setCount(count +1);}return(<buttononClick={handleClick}> You pressed me{count} times</button>);}
Updating state based on the previous state
Suppose theage is42. This handler callssetAge(age + 1) three times:
functionhandleClick(){
setAge(age +1);// setAge(42 + 1)
setAge(age +1);// setAge(42 + 1)
setAge(age +1);// setAge(42 + 1)
}However, after one click,age will only be43 rather than45! This is because calling theset functiondoes not update theage state variable in the already running code. So eachsetAge(age + 1) call becomessetAge(43).
To solve this problem,you may pass anupdater function tosetAge instead of the next state:
functionhandleClick(){
setAge(a=>a + 1);// setAge(42 => 43)
setAge(a=>a + 1);// setAge(43 => 44)
setAge(a=>a + 1);// setAge(44 => 45)
}Here,a => a + 1 is your updater function. It takes thepending state and calculates thenext state from it.
React puts your updater functions in aqueue. Then, during the next render, it will call them in the same order:
a => a + 1will receive42as the pending state and return43as the next state.a => a + 1will receive43as the pending state and return44as the next state.a => a + 1will receive44as the pending state and return45as the next state.
There are no other queued updates, so React will store45 as the current state in the end.
By convention, it’s common to name the pending state argument for the first letter of the state variable name, likea forage. However, you may also call it likeprevAge or something else that you find clearer.
React maycall your updaters twice in development to verify that they arepure.
Deep Dive
You might hear a recommendation to always write code likesetAge(a => a + 1) if the state you’re setting is calculated from the previous state. There is no harm in it, but it is also not always necessary.
In most cases, there is no difference between these two approaches. React always makes sure that for intentional user actions, like clicks, theage state variable would be updated before the next click. This means there is no risk of a click handler seeing a “stale”age at the beginning of the event handler.
However, if you do multiple updates within the same event, updaters can be helpful. They’re also helpful if accessing the state variable itself is inconvenient (you might run into this when optimizing re-renders).
If you prefer consistency over slightly more verbose syntax, it’s reasonable to always write an updater if the state you’re setting is calculated from the previous state. If it’s calculated from the previous state of someother state variable, you might want to combine them into one object anduse a reducer.
Example 1 of 2:Passing the updater function
This example passes the updater function, so the “+3” button works.
import{useState}from'react';exportdefaultfunctionCounter(){const[age,setAge] =useState(42);functionincrement(){setAge(a=>a +1);}return(<><h1>Your age:{age}</h1><buttononClick={()=>{increment();increment();increment();}}>+3</button><buttononClick={()=>{increment();}}>+1</button></>);}
Updating objects and arrays in state
You can put objects and arrays into state. In React, state is considered read-only, soyou shouldreplace it rather thanmutate your existing objects. For example, if you have aform object in state, don’t mutate it:
// 🚩 Don't mutate an object in state like this:
form.firstName ='Taylor';Instead, replace the whole object by creating a new one:
// ✅ Replace state with a new object
setForm({
...form,
firstName:'Taylor'
});Readupdating objects in state andupdating arrays in state to learn more.
Example 1 of 4:Form (object)
In this example, theform state variable holds an object. Each input has a change handler that callssetForm 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';exportdefaultfunctionForm(){const[form,setForm] =useState({firstName:'Barbara',lastName:'Hepworth',email:'bhepworth@sculpture.com',});return(<><label> First name:<inputvalue={form.firstName}onChange={e=>{setForm({...form,firstName:e.target.value});}}/></label><label> Last name:<inputvalue={form.lastName}onChange={e=>{setForm({...form,lastName:e.target.value});}}/></label><label> Email:<inputvalue={form.email}onChange={e=>{setForm({...form,email:e.target.value});}}/></label><p>{form.firstName}{' '}{form.lastName}{' '} ({form.email})</p></>);}
Avoiding recreating the initial state
React saves the initial state once and ignores it on the next renders.
functionTodoList(){
const[todos,setTodos] =useState(createInitialTodos());
// ...Although the result ofcreateInitialTodos() is only used for the initial render, you’re still calling this function on every render. This can be wasteful if it’s creating large arrays or performing expensive calculations.
To solve this, you maypass it as aninitializer function touseState instead:
functionTodoList(){
const[todos,setTodos] =useState(createInitialTodos);
// ...Notice that you’re passingcreateInitialTodos, which is thefunction itself, and notcreateInitialTodos(), which is the result of calling it. If you pass a function touseState, React will only call it during initialization.
React maycall your initializers twice in development to verify that they arepure.
Example 1 of 2:Passing the initializer function
This example passes the initializer function, so thecreateInitialTodos function only runs during initialization. It does not run when component re-renders, such as when you type into the input.
import{useState}from'react';functioncreateInitialTodos(){constinitialTodos =[];for(leti =0;i <50;i++){initialTodos.push({id:i,text:'Item ' +(i +1)});}returninitialTodos;}exportdefaultfunctionTodoList(){const[todos,setTodos] =useState(createInitialTodos);const[text,setText] =useState('');return(<><inputvalue={text}onChange={e=>setText(e.target.value)}/><buttononClick={()=>{setText('');setTodos([{id:todos.length,text:text},...todos]);}}>Add</button><ul>{todos.map(item=>(<likey={item.id}>{item.text}</li>))}</ul></>);}
Resetting state with a key
You’ll often encounter thekey attribute whenrendering lists. However, it also serves another purpose.
You canreset a component’s state by passing a differentkey to a component. In this example, the Reset button changes theversion state variable, which we pass as akey to theForm. When thekey changes, React re-creates theForm component (and all of its children) from scratch, so its state gets reset.
Readpreserving and resetting state to learn more.
import{useState}from'react';exportdefaultfunctionApp(){const[version,setVersion] =useState(0);functionhandleReset(){setVersion(version +1);}return(<><buttononClick={handleReset}>Reset</button><Formkey={version}/></>);}functionForm(){const[name,setName] =useState('Taylor');return(<><inputvalue={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
useMemoHook can help. - If you want to reset the entire component tree’s state,pass a different
keyto 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 aset function while your component is rendering.
Here’s an example. ThisCountLabel component displays thecount prop passed to it:
exportdefaultfunctionCountLabel({count}){
return<h1>{count}</h1>
}Say you want to show whether the counter hasincreased or decreased since the last change. Thecount prop doesn’t tell you this — you need to keep track of its previous value. Add theprevCount state variable to track it. Add another state variable calledtrend to hold whether the count has increased or decreased. CompareprevCount withcount, and if they’re not equal, update bothprevCount andtrend. Now you can show both the current count prop andhow it has changed since the last render.
import{useState}from'react';exportdefaultfunctionCountLabel({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 aset function while rendering, it must be inside a condition likeprevCount !== count, and there must be a call likesetPrevCount(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 thecurrently rendering component like this. Calling theset function ofanother component during rendering is an error. Finally, yourset call should stillupdate state without mutation — this doesn’t mean you can break other rules ofpure 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 theset function during render, React will re-render that component immediately after your component exits with areturn 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). If your condition is below all the Hook calls, you may add an earlyreturn; to restart rendering earlier.
Troubleshooting
I’ve updated the state, but logging gives me the old value
Calling theset functiondoes not change state in the running code:
functionhandleClick(){
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 becausestates behaves like a snapshot. Updating state requests another render with the new state value, but does not affect thecount 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 theset function:
constnextCount =count +1;
setCount(nextCount);
console.log(count);// 0
console.log(nextCount);// 1I’ve updated the state, but the screen doesn’t update
React willignore your update if the next state is equal to the previous state, as determined by anObject.is comparison. This usually happens when you change an object or an array in state directly:
obj.x =10;// 🚩 Wrong: mutating existing object
setObj(obj);// 🚩 Doesn't do anythingYou mutated an existingobj object and passed it back tosetObj, so React ignored the update. To fix this, you need to ensure that you’re alwaysreplacing objects and arrays in state instead ofmutating them:
// ✅ Correct: creating a new object
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 stateduring 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<buttononClick={handleClick()}>Click me</button>
// ✅ Correct: passes down the event handler
return<buttononClick={handleClick}>Click me</button>
// ✅ Correct: passes down an inline function
return<buttononClick={(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 specificset function call responsible for the error.
My initializer or updater function runs twice
InStrict Mode, React will call some of your functions twice instead of once:
functionTodoList(){
// This component function will run twice for every render.
const[todos,setTodos] =useState(()=>{
// This initializer function will run twice during initialization.
returncreateTodos();
});
functionhandleClick(){
setTodos(prevTodos=>{
// This updater function will run twice for every click.
return[...prevTodos,createTodo()];
});
}
// ...This is expected and shouldn’t break your code.
Thisdevelopment-only behavior helps youkeep components pure. React uses the result of one of the calls, and ignores the result of the other call. As long as your component, initializer, and updater functions are pure, this shouldn’t affect your logic. However, if they are accidentally impure, this helps you notice the mistakes.
For example, this impure updater function mutates an array in state:
setTodos(prevTodos=>{
// 🚩 Mistake: mutating state
prevTodos.push(createTodo());
});Because React calls your updater function twice, you’ll see the todo was added twice, so you’ll know that there is a mistake. In this example, you can fix the mistake byreplacing the array instead of mutating it:
setTodos(prevTodos=>{
// ✅ Correct: replacing with new state
return[...prevTodos,createTodo()];
});Now that this updater function is pure, calling it an extra time doesn’t make a difference in behavior. This is why React calling it twice helps you find mistakes.Only component, initializer, and updater functions need to be pure. Event handlers don’t need to be pure, so React will never call your event handlers twice.
Readkeeping components pure to learn more.
I’m trying to set state to a function, but it gets called instead
You can’t put a function into state like this:
const[fn,setFn] =useState(someFunction);
functionhandleClick(){
setFn(someOtherFunction);
}Because you’re passing a function, React assumes thatsomeFunction is aninitializer function, and thatsomeOtherFunction is anupdater function, so it tries to call them and store the result. To actuallystore a function, you have to put() => before them in both cases. Then React will store the functions you pass.
const[fn,setFn] =useState(()=>someFunction);
functionhandleClick(){
setFn(()=>someOtherFunction);
}