// ✅
function MyComponent() {
const [count, setCount] = useState(0);
// ...
}
// ❌
if (condition) {
useEffect(() => {});
}React relies on consistent hook call order across renders.
Common React Hooks mistakes, stale closure issues, dependency pitfalls, and practical best practices.
Avoid invalid hook usage.
// ✅
function MyComponent() {
const [count, setCount] = useState(0);
// ...
}
// ❌
if (condition) {
useEffect(() => {});
}React relies on consistent hook call order across renders.
function useOnlineStatus() {
const [isOnline, setIsOnline] = useState(true);
return isOnline;
}A custom hook is just a function whose body legitimately uses other hooks.
npm install -D eslint-plugin-react-hooksThe hooks ESLint plugin catches hook order problems and effect dependency issues.
Common dependency and stale closure issues.
Effects and callbacks capture values from the render where they were created.
useEffect(() => {
const id = setInterval(() => {
console.log(count); // can go stale if dependencies are wrong
}, 1000);
return () => clearInterval(id);
}, [count]);If the effect depends on `count`, include it or restructure the code to avoid stale reads.
Avoid recreating dependency objects every render when identity matters.
const options = useMemo(() => ({ roomId, serverUrl }), [roomId, serverUrl]);
useEffect(() => {
const conn = createConnection(options);
conn.connect();
return () => conn.disconnect();
}, [options]);Changing object identity retriggers effects even when fields look the same.
useEffect(() => {
subscribe(userId);
return () => unsubscribe(userId);
}, [userId]);Effects are easier to reason about when they do only synchronization and cleanup.
Avoid over-memoization and unnecessary effects.
// Not every derived value needs useMemo.
const fullName = `${firstName} ${lastName}`;Simple computations are often cheaper and clearer without `useMemo`.
// Prefer deriving directly:
const filtered = items.filter(item => item.active);
// Instead of syncing derived state in an effect.If something can be calculated from current props/state, compute it during render rather than syncing another state variable.
Do not move user-triggered logic into effects unnecessarily.
function handleSave() {
saveDraft(form);
}
<button onClick={handleSave}>Save</button>Effects should synchronize with external systems because rendering happened, not because you want to run arbitrary imperative code later.