What is the difference between useState and useEffect in React?
useState stores and updates component state that drives re-renders; useEffect runs side effects (data fetching, subscriptions) after renders.
React
Overview
`useState` and `useEffect` are the two most-used React hooks. `useState` manages data that the component needs to remember between renders. `useEffect` handles side effects things that happen outside the React render cycle, like fetching data, setting timers, or subscribing to events.
Key Points
- ā¢`useState(initial)` returns `[value, setter]`. Calling the setter triggers a re-render.
- ā¢`useEffect(fn, deps)` runs `fn` after every render where a dependency changed.
- ā¢Empty deps `[]`: runs once after mount. No deps array: runs after every render.
- ā¢Return a cleanup function from `useEffect` to cancel subscriptions or timers on unmount.
- ā¢Do not update state inside `useEffect` without a condition it causes infinite loops.
Examples
useState: counter
tsximport { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
return (
<button onClick={() => setCount(c => c + 1)}>
Clicked {count} times
</button>
);
}useEffect: fetch data on mount
tsximport { useState, useEffect } from 'react';
function UserProfile({ userId }: { userId: number }) {
const [user, setUser] = useState(null);
useEffect(() => {
let cancelled = false;
fetch(`/api/users/${userId}`)
.then(r => r.json())
.then(data => { if (!cancelled) setUser(data); });
return () => { cancelled = true; }; // cleanup on unmount or userId change
}, [userId]); // re-fetch when userId changes
if (!user) return <p>Loadingā¦</p>;
return <p>{user.name}</p>;
}useEffect with cleanup: event listener
tsxuseEffect(() => {
const handler = (e: KeyboardEvent) => {
if (e.key === 'Escape') closeModal();
};
window.addEventListener('keydown', handler);
return () => window.removeEventListener('keydown', handler); // cleanup
}, []);Pro Tip
A missing dependency in the deps array is one of the most common React bugs it causes stale closures. Use the `eslint-plugin-react-hooks` exhaustive-deps rule to catch them automatically.