In short
Every React screen runs on two kinds of data. Props come in from the parent and are read-only. State belongs to the component and changes over time. Mix them up and your UI stops updating.
Props pass data down from parent to child; state is data a component owns and can change over time via `useState` — together they drive everything a React UI displays.

Think of it like this
Pocket money vs your piggy bank
Pocket money is decided by your parents. You can spend it but you can't change the amount they gave. Your piggy bank is yours: you add coins and the count goes up. Props are the pocket money. State is the piggy bank.
Watch it happen
Clicking + on a cart item
props: qty=1, onChange
1/5CartItem owns the qty state and passes it down as a prop, along with a function to change it.
The big ideas
What you need to know
Props flow down
A parent passes data to a child like function arguments. The child must never modify them.
State changes trigger re-renders
Calling the setter from useState tells React to run the component again with the new value.
Events flow up via callbacks
To change a parent's state, pass a function as a prop. The child calls it, the parent updates.
Server data becomes state
Data fetched from your API usually lands in state, so the UI updates once the response arrives.
See it in code
Walk through the code
1import { useState } from "react";2 3function QtyPicker({ qty, onChange }) {4 return (5 <div>6 <button onClick={() => onChange(qty - 1)} disabled={qty <= 1}>-</button>7 <span>{qty}</span>8 <button onClick={() => onChange(qty + 1)}>+</button>9 </div>10 );11}12 13export default function CartItem({ product }) {14 const [qty, setQty] = useState(1);15 return <><h3>{product.name}</h3><QtyPicker qty={qty} onChange={setQty} /></>;16}1/3The child reads qty and onChange from props. Clicking calls onChange with the new number.
QtyPicker has no state of its own. It shows what it's told and reports clicks upward.
Save yourself the pain
Common mistakes
Oops
Changing state directly, like cart.push(item), and wondering why nothing re-renders.
Do this instead
Create a new value and call the setter: setCart([...cart, item]). React compares references to detect change.
Oops
Copying a prop into state with useState(props.qty), then the parent's updates never show.
Do this instead
Use the prop directly unless you truly need a separate editable copy.
Your mission
Lift the state up
Quick check
A child component needs to change a value that its parent displays. What's the React way?
Go deeper
- 1Build a component that receives data via props and displays it.
- 2Build a counter or toggle using `useState` to internalize how state updates trigger re-renders.
- 3Practice lifting state up to a shared parent when two sibling components need the same data.
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.