useState Hook basic usage
The useState Hook lets you declare a state variable in a component. It takes the initial state as an argument and returns a pair of values: the current state, and a setter function that lets you update it. Example: const [index, setIndex] = useState(0); declares a state variable index with initial value 0 and a setter function setIndex.
State initialization with useState
When calling useState, pass the initial value for the state variable as an argument. The Hook returns an array with two elements: the current state value and a function to update it. Example: const [showMore, setShowMore] = useState(false) initializes showMore to false.
Each component instance has independent state
If you render the same component multiple times, each instance will get its own independent state. Changes to one component's state do not affect other instances of the same component.
useState hook import and usage
To add state to a component, import `useState` from React: `import { useState } from 'react';`. Inside your component, declare a state variable using `const [value, setValue] = useState(initialValue)`. The convention is to name the setter function `set` followed by the state variable name.
useState returns current state and setter function
The `useState` hook returns two values: the current state value and a function to update it. Call the setter function with the new value to update the state. When state updates, React re-renders the component with the new value.
Example: Form component with state and event handlers
import { useState } from 'react';
export default function Form() {
const [answer, setAnswer] = useState('');
const [error, setError] = useState(null);
const [status, setStatus] = useState('typing');
if (status === 'success') {
return <h1>That's right!</h1>
}
async function handleSubmit(e) {
e.preventDefault();
setStatus('submitting');
try {
await submitForm(answer);
setStatus('success');
} catch (err) {
setStatus('typing');
setError(err);
}
}
function handleTextareaChange(e) {
setAnswer(e.target.value);
}
return (
<>
<h2>City quiz</h2>
<p>
In which city is there a billboard that turns air into drinkable water?
</p>
<form onSubmit={handleSubmit}>
<textarea
value={answer}
onChange={handleTextareaChange}
disabled={status === 'submitting'}
/>
<br />
<button disabled={
answer.length === 0 ||
status === 'submitting'
}>
Submit
</button>
{error !== null &&
<p className="Error">
{error.message}
</p>
}
</form>
</>
);
}
function submitForm(answer) {
return new Promise((resolve, reject) => {
setTimeout(() => {
let shouldError = answer.toLowerCase() !== 'lima'
if (shouldError) {
reject(new Error('Good guess but a wrong answer. Try again!'));
} else {
resolve();
}
}, 1500);
});
}
This example shows a form that manages three state variables: answer (the user input), error (for displaying error messages), and status (one of 'typing', 'submitting', or 'success'). Event handlers update state based on user interaction and async operations.
Example: Picture with toggle state and event propagation
import { useState } from 'react';
export default function Picture() {
const [isActive, setIsActive] = useState(false);
let backgroundClassName = 'background';
let pictureClassName = 'picture';
if (isActive) {
pictureClassName += ' picture--active';
} else {
backgroundClassName += ' background--active';
}
return (
<div
className={backgroundClassName}
onClick={() => setIsActive(false)}
>
<img
onClick={e => {
e.stopPropagation();
setIsActive(true);
}}
className={pictureClassName}
alt="Rainbow houses in Kampung Pelangi, Indonesia"
src="https://react.dev/images/docs/scientists/5qwVYb1.jpeg"
/>
</div>
);
}
This example demonstrates managing CSS classes based on state and using e.stopPropagation() to prevent click events on the image from bubbling up to the parent div's click handler. The visual appearance changes depending on the isActive state.
Example: Profile editor with conditional rendering
import { useState } from 'react';
export default function EditProfile() {
const [isEditing, setIsEditing] = useState(false);
const [firstName, setFirstName] = useState('Jane');
const [lastName, setLastName] = useState('Jacobs');
return (
<form onSubmit={e => {
e.preventDefault();
setIsEditing(!isEditing);
}}>
<label>
First name:{' '}
{isEditing ? (
<input
value={firstName}
onChange={e => {
setFirstName(e.target.value)
}}
/>
) : (
<b>{firstName}</b>
)}
</label>
<label>
Last name:{' '}
{isEditing ? (
<input
value={lastName}
onChange={e => {
setLastName(e.target.value)
}}
/>
) : (
<b>{lastName}</b>
)}
</label>
<button type="submit">
{isEditing ? 'Save' : 'Edit'} Profile
</button>
<p><i>Hello, {firstName} {lastName}!</i></p>
</form>
);
}
This example shows how to use conditional rendering with state to switch between viewing mode (showing text) and editing mode (showing inputs). The button label and displayed content change based on the isEditing boolean state.
Gallery example with single state variable
Example showing useState with one state variable: const [index, setIndex] = useState(0); function handleClick() { setIndex(index + 1); } This makes the component remember and update the current index on user interaction.
Gallery example with multiple state variables
Example showing multiple state variables in one component: const [index, setIndex] = useState(0); const [showMore, setShowMore] = useState(false); function handleNextClick() { setIndex(index + 1); } function handleMoreClick() { setShowMore(!showMore); } This demonstrates managing both a number and boolean state.
Hooks must be called at the top level of component functions
Hooks like useState must be called unconditionally at the top level of a component function, not inside conditions, loops, or nested functions. All Hook calls must happen before the first return statement and always in the same order.
Calling useState inside a condition breaks Hook rules
Placing useState calls inside an if statement causes the component to render fewer hooks than expected on different renders, resulting in an error. This violates the rule that Hooks must be called unconditionally at the top level.
Convert regular variables to useState
To fix a component that uses regular variables instead of state: import useState from React, replace variable declarations with const [variable, setVariable] = useState(initialValue), and replace assignments like variable = value with setVariable(value).
Example: Correct Hook placement with conditional rendering
import { useState } from 'react';
export default function FeedbackForm() {
const [isSent, setIsSent] = useState(false);
const [message, setMessage] = useState('');
if (isSent) {
return <h1>Thank you!</h1>;
}
return (
<form onSubmit={e => {
e.preventDefault();
alert(`Sending: "${message}"`);
setIsSent(true);
}}>
<textarea
placeholder="Message"
value={message}
onChange={e => setMessage(e.target.value)}
/>
<br />
<button type="submit">Send</button>
</form>
);
}
This example shows the correct way to place Hook calls before any conditional returns, even when the component has conditional rendering logic.
Example: Form with input state using useState
import { useState } from 'react';
export default function Form() {
const [firstName, setFirstName] = useState('');
const [lastName, setLastName] = useState('');
function handleFirstNameChange(e) {
setFirstName(e.target.value);
}
function handleLastNameChange(e) {
setLastName(e.target.value);
}
function handleReset() {
setFirstName('');
setLastName('');
}
return (
<form onSubmit={e => e.preventDefault()}>
<input
placeholder="First name"
value={firstName}
onChange={handleFirstNameChange}
/>
<input
placeholder="Last name"
value={lastName}
onChange={handleLastNameChange}
/>
<h1>Hi, {firstName} {lastName}</h1>
<button onClick={handleReset}>Reset</button>
</form>
);
}
This example demonstrates using multiple state variables with useState, updating them in event handlers, and resetting them in a reset handler.
useState Hook returns two values
The useState Hook returns an array with exactly two items: the current state variable value and a setter function to update it. The syntax uses array destructuring: const [stateValue, setStateValue] = useState(initialValue).
State variable initial value
The only argument to useState is the initial value of the state variable. On first render, useState returns this initial value. On subsequent renders, it returns the current state value that was set by the setter function.
Multiple state variables in one component
A component can have multiple state variables of different types. Each useState call creates a separate state variable. For example, a component can have both a number state (index) and a boolean state (showMore).
Import useState from React
To use the useState Hook, import it from 'react' at the top of the file: import { useState } from 'react';
Hooks can only be called at top level
Hooks (functions starting with 'use', like useState) can only be called at the top level of components or other Hooks. They cannot be called inside conditions, loops, or nested functions. This is necessary for React to match hook calls to state values across renders.
React state maintained by call order
React matches state values to useState calls based on their consistent order on each render. This is why Hooks must always be called in the same order—React maintains an array of state pairs for each component and increments through them as each Hook is called.
Naming convention for state variables
The convention for naming state variables is const [something, setSomething] = useState(initialValue). Following this convention makes code easier to understand across projects, though any name is technically valid.
useState with complex discriminated union state
type RequestState =
| { status: 'idle' }
| { status: 'loading' }
| { status: 'success', data: any }
| { status: 'error', error: Error };
const [requestState, setRequestState] = useState<RequestState>({ status: 'idle' });
useState type inference in TypeScript
The useState Hook infers the type of state from the initial value passed to it. For example, useState(false) infers the type as boolean. You can explicitly provide a type argument using useState<boolean>(false).
useState with union types example
type Status = "idle" | "loading" | "success" | "error";
const [status, setStatus] = useState<Status>("idle");
useState hook initializes and manages component state
The useState hook is imported from 'react' and called inside a component to add state. It takes an initial value and returns an array with two elements: the current state value and a function to update that state. Example: const [value, setValue] = useState(null) initializes value to null and provides setValue to update it.