Props vs State in React
Answer
Props and State are both plain JavaScript objects that control a component's output, but they have different purposes and behaviors.
Key Differences
| Aspect | Props | State |
|---|---|---|
| Origin | From parent component | Internal to component |
| Mutable | No (read-only) | Yes (via setState/setter) |
| Purpose | Configuration | Interactive data |
| Updates | Parent changes them | Component changes itself |
| Re-render | Yes, when props change | Yes, when state changes |
Props Example
// Parent passes props
function App() {
return <UserCard name="John" age={30} isAdmin={true} />;
}
// Child receives props
function UserCard({ name, age, isAdmin }) {
// ❌ Cannot modify props
// name = "Jane"; // Wrong!
return (
<div>
<h2>{name}</h2>
<p>Age: {age}</p>
{isAdmin && <span>Admin</span>}
</div>
);
}
State Example
function Counter() {
const [count, setCount] = useState(0);
// ✅ Can modify state via setter
const increment = () => {
setCount(count + 1);
};
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>+1</button>
</div>
);
}
Props for Configuration, State for Interaction
// Props configure initial behavior
// State handles user interaction
function SearchInput({ placeholder, onSearch }) {
const [query, setQuery] = useState("");
const handleSubmit = () => {
onSearch(query); // Callback prop
};
return (
<div>
<input
placeholder={placeholder} // From props
value={query} // From state
onChange={(e) => setQuery(e.target.value)}
/>
<button onClick={handleSubmit}>Search</button>
</div>
);
}
// Usage
<SearchInput
placeholder="Search..." // Prop
onSearch={(q) => console.log(q)} // Callback prop
/>;
Data Flow
function Parent() {
const [user, setUser] = useState({ name: "John" });
const updateName = (newName) => {
setUser({ ...user, name: newName });
};
return (
<div>
<DisplayUser user={user} /> {/* Props down */}
<EditUser user={user} onUpdate={updateName} /> {/* Callback up */}
</div>
);
}
function DisplayUser({ user }) {
return <h1>{user.name}</h1>;
}
function EditUser({ user, onUpdate }) {
return <input value={user.name} onChange={(e) => onUpdate(e.target.value)} />;
}
Common Patterns
Derived State from Props (Avoid!)
// ❌ Anti-pattern: Copying props to state
function User({ userProp }) {
const [user, setUser] = useState(userProp);
// Bug: Won't update when userProp changes!
}
// ✅ Good: Use prop directly or derive in render
function User({ user }) {
const fullName = `${user.firstName} ${user.lastName}`;
return <h1>{fullName}</h1>;
}
// ✅ Or use key to reset when prop changes
<UserForm user={user} key={user.id} />;
Lifting State Up
// Two children need same data? Lift state to parent
function Parent() {
const [temperature, setTemperature] = useState(20);
return (
<div>
<Thermometer temp={temperature} onChange={setTemperature} />
<TemperatureDisplay temp={temperature} />
</div>
);
}
Key Points
- Props: External data passed in (read-only)
- State: Internal data managed by component
- Props flow down, callbacks flow up
- Never modify props directly
- State changes trigger re-renders
- Lift state to share between siblings