In short
Props come from outside. State is the component's own memory, like what's typed in a box or whether a menu is open. Change it and React redraws that part of the screen.
Data that a component owns and can change over time via `useState`, triggering a re-render whenever it's updated.

Think of it like this
The station display board
When a train's platform changes, the railway updates the board and everyone looking sees the new number. Nobody repaints the board by hand. In React you update state, and React repaints the screen for you.
Watch it happen
One click, one re-render
click
1/5You click the button, and Counter's addThree handler runs.
The big ideas
What you need to know
useState gives a value and a setter
const [count, setCount] = useState(0). Read count, and call setCount to change it.
Setting state re-renders
Calling the setter tells React to run your component again and update the screen with the new value.
State is a snapshot
Inside one render, count never changes. The new value shows up in the next render.
Replace, don't mutate
For objects and arrays, make a new copy with spread. Changing the old one in place won't trigger a re-render.
See it in code
Walk through the code
1import { useState } from "react";2 3export default function Counter() {4 const [count, setCount] = useState(0);5 6 function addThree() {7 setCount((c) => c + 1);8 setCount((c) => c + 1);9 setCount((c) => c + 1);10 }11 12 return <button onClick={addThree}>Clicked {count} times</button>;13}1/3useState(0) gives the current count and a setter. It starts at 0.
The updater form (c) => c + 1 always gets the latest value, so one click adds 3. Writing setCount(count + 1) three times would add only 1.
Save yourself the pain
Common mistakes
Oops
Doing todos.push(newTodo) and then setTodos(todos).
Do this instead
Create a new array: setTodos([...todos, newTodo]). React compares references, so the same array means no re-render.
Oops
Calling setCount and expecting count to change on the very next line.
Do this instead
count is a snapshot for this render. Use the new value directly, or read it in the next render.
Your mission
Build a like button
Quick check
count is 0. One click runs setCount(count + 1) three times. What does the button show?
Go deeper
- 1Build a counter component to internalize how `useState` triggers re-renders.
- 2Learn why you should never mutate state directly — always use the setter.
- 3Practice the functional updater form (`setCount(c => c + 1)`) for state that depends on the previous value.
More topics at this stop
Stuck on this topic? Ask an Insider
Get 1:1 guidance from people who've walked this exact path — on the InsideEdge app.