Before diving into examples, it's important to clearly understand the difference between state and ref in React.
π΅ State vs π΄ Ref (Quick Intuition)
π΅ State represents data that defines your UI. Changes trigger a re-render, React fully controls the UI, and it is used for application logic. π If it affects what the user should see based on app status, it should be state.
π΄ Ref is a direct reference to a DOM element or a mutable value. It does not trigger a re-render, React does not track its changes, and it is used for imperative actions. π If it's just a direct DOM interaction or a temporary effect, a ref is enough.
π΅ 1. State β React-controlled UI
State means React renders the UI based on data changes. Use cases: like/unlike, modal open/close, delete state, form handling.
const [isLiked, setIsLiked] = useState(false);
<button onClick={() => setIsLiked(!isLiked)}>
{isLiked ? "β€οΈ Liked" : "π€ Like"}
</button>π The UI is fully driven by state.
π΄ 2. Ref β Direct DOM control
A ref lets you manipulate DOM elements without re-rendering React. Use cases: focusing inputs, scrolling, imperative animations, temporary DOM effects.
const btnRef = useRef(null);
btnRef.current.style.transform = "scale(0.9)";π React is not aware of this change.
π’ 3. CSS β Best for visual effects
CSS is the simplest and most efficient way to create UI effects: hover effects, transitions, animations and click feedback.
.delete-btn:active {
transform: scale(0.9);
background-color: red;
}π No JavaScript needed.
βοΈ The Key Insight
Not everything in the UI should be state. Choosing the wrong approach leads to unnecessary re-renders, messy logic and hard-to-debug UI behavior.
π§© Real Example: Delete Button Flash
In a React project, I needed a delete button that shows a quick red flash before removing an item.
β Wrong: using state for everything
const [isFlashing, setIsFlashing] = useState(false);Problem: an unnecessary re-render β overkill for a 200 ms visual effect.
β Mixed: state + ref
// effect on the button
btnRef.current.style.backgroundColor = "red";
// delete the whole component
setIsDeleting(true);Problem: two sources of truth and inconsistent UI behavior.
β Correct: CSS + class toggle
const handleDeleteClick = (e) => {
const btn = e.currentTarget;
btn.classList.add("flash");
setIsDeleting(true);
setTimeout(() => {
btn.classList.remove("flash");
handleDelete(id);
}, 200);
};.delete-btn.flash {
background-color: red;
transform: scale(0.9);
}π― Final Takeaway
- State β for real application data
- Ref β for direct DOM manipulation
- CSS β for simple visual effects
π‘ If something does not represent application state, it probably should not be state.



