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/offwith a single button.
- Make a controlled text input that mirrors its value live.
- Add a stepprop to the counter and default it to1.