React - useState (Basics)
Goal
Understand and use the useState
hook to manage local component state in React.
When to use it
- To store values that change over time within a component (e.g., input values, toggles, counters).
- When re-rendering the UI should reflect the latest state.
Minimal pattern
const { useState } = React;
function Counter(){
const [count, setCount] = useState(0); // 0 is the initial state
return (
<div>
<p>Count: <strong>{count}</strong></p>
<button onClick={() => setCount(count + 1)}>+1</button>
</div>
);
}
Try it
View source
const { useState } = React;
function Counter({ step = 1 }){
const [count, setCount] = useState(0);
return (
<div>
<p>Count: <strong>{count}</strong></p>
<button onClick={() => setCount(c => c + step)}>+{step}</button>
<button onClick={() => setCount(c => c - step)} style={{marginLeft:8}}>-{step}</button>
<button onClick={() => setCount(0)} style={{marginLeft:8}}>Reset</button>
</div>
);
}
const root = ReactDOM.createRoot(document.getElementById('try-usestate'));
root.render(<>
<Counter step={1} />
<Counter step={5} />
</>);
Syntax primer (for newcomers)
const [value, setValue] = useState(initial)
: Array destructuring returns the current state and a setter.setValue(next)
: Triggers a re-render with new state. You can pass a value or a function.setValue(v => v + 1)
: Functional updates use the latest state safely (recommended when next depends on previous).
Common pitfalls
- Do not mutate state:
value++;
won’t re-render. Always call the setter. - State updates are asynchronous: read the latest value by using the functional form
setValue(v => ...)
when deriving from previous. - Each component instance has its own state; siblings do not share state unless lifted to a parent.
Exercises
- Build a toggle component:
on/off
with a single button. - Make a controlled text input that mirrors its value live.
- Add a
step
prop to the counter and default it to1
.