Introduction
State is data that a component owns and manages internally, and that can change over the component's lifetime. Unlike props, which are passed in from outside and are read-only, state is local, mutable (through its updater function), and private to the component that declares it. When state changes, React re-renders the component to reflect the new data in the UI.
Cricket analogy: A batter's personal running tally of runs today is state they own and update themselves, while the match format (T20 rules) is like props handed down and read-only; when the tally changes, the scoreboard (UI) re-renders.
Syntax
import { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}Explanation
The useState hook returns a pair: the current state value and a function to update it. Calling the updater function schedules a re-render with the new value. State updates should always go through the updater function — directly mutating the state variable will not trigger a re-render and breaks React's rendering model. Each component instance maintains its own independent state.
Cricket analogy: useState is like a scorer who hands you both the current total and a chalk to update it; scribbling a new number directly on the board without telling the official scorer doesn't count toward the match record, just as mutating state directly skips React's re-render.
Example
function TodoInput() {
const [text, setText] = useState('');
const [todos, setTodos] = useState([]);
const addTodo = () => {
if (text.trim() === '') return;
setTodos([...todos, text]);
setText('');
};
return (
<div>
<input value={text} onChange={(e) => setText(e.target.value)} />
<button onClick={addTodo}>Add</button>
<ul>
{todos.map((todo, i) => (
<li key={i}>{todo}</li>
))}
</ul>
</div>
);
}Output
Typing into the input updates the text state on every keystroke, making the input a controlled component. Clicking "Add" appends the current text to the todos array state and clears the input. Each state update triggers a re-render, so the list of <li> items and the input value always reflect the latest state.
Cricket analogy: Watching the required-run-rate figure update after every single run scored is like the text state updating on every keystroke, and confirming the final total when the innings ends mirrors clicking 'Add' to append text into the todos array and clear the input.
Key Takeaways
- State is local, mutable data owned by a component, managed via useState (or useReducer).
- Always update state through its setter function, never by direct mutation.
- Updating state triggers a re-render so the UI stays in sync with data.
- State is private to a component; to share it, it must be lifted to a common ancestor.
- Props are read-only inputs from a parent; state is internal and owned by the component itself.
Practice what you learned
1. Which hook is most commonly used to add local state to a function component?
2. What happens when a state setter function is called?
3. Why should you avoid directly mutating a state variable (e.g. array.push)?
4. How does state differ from props?
5. In the TodoInput example, what makes the text input a 'controlled component'?
Was this page helpful?
You May Also Like
Props in React
Learn how props pass read-only data from parent to child components in React's one-way data flow model.
The useState Hook
Master useState, the Hook that adds local state to function components, including initial values, updater functions, and functional updates.
Lifting State Up in React
Learn the pattern of moving shared state to the closest common ancestor so sibling components can stay in sync.
Controlled vs Uncontrolled Components
Compare controlled components, where React state drives form values, with uncontrolled components that rely on the DOM and refs.
Related Reading
Related Study Notes in Web Development
Browse all study notesWebSockets Study Notes
Web Development · 30 topics
Web DevelopmentWebAssembly Study Notes
WebAssembly · 30 topics
Web DevelopmentgRPC Study Notes
Protocol Buffers · 30 topics
Web DevelopmentSpring Boot Study Notes
Java · 30 topics
Web DevelopmentFlask Study Notes
Python · 30 topics
Web DevelopmentDjango Study Notes
Python · 30 topics