React Hooks Pitfalls and Best Practices

Common React Hooks mistakes, stale closure issues, dependency pitfalls, and practical best practices.

View
StandardDetailedCompact
Export
Copy the compact sheet, download it, or print it.
Download
`D` dense toggle · `C` copy all
## Rules of Hooks
Call hooks only at the top level
// ✅
function MyComponent() {
  const [count, setCount] = useState(0);
  // ...
}

// ❌
if (condition) {
  useEffect(() => {});
}

# Do not call hooks in conditions, loops, or nested functions.

Call hooks only from components or custom hooks
function useOnlineStatus() {
  const [isOnline, setIsOnline] = useState(true);
  return isOnline;
}

# Do not call hooks from regular utility functions.

Enable eslint-plugin-react-hooks
npm install -D eslint-plugin-react-hooks

# Catch rules-of-hooks and dependency mistakes early.

## Effect Dependency Pitfalls
Stale closure pitfall
useEffect(() => {
  const id = setInterval(() => {
    console.log(count); // can go stale if dependencies are wrong
  }, 1000);
  return () => clearInterval(id);
}, [count]);

# Effects and callbacks capture values from the render where they were created.

Memoize objects used in dependencies
const options = useMemo(() => ({ roomId, serverUrl }), [roomId, serverUrl]);
useEffect(() => {
  const conn = createConnection(options);
  conn.connect();
  return () => conn.disconnect();
}, [options]);

# Avoid recreating dependency objects every render when identity matters.

Move non-reactive logic out of effects
useEffect(() => {
  subscribe(userId);
  return () => unsubscribe(userId);
}, [userId]);

# Keep effects focused on synchronization.

## Performance Pitfalls
Do not memoize everything
// Not every derived value needs useMemo.
const fullName = `${firstName} ${lastName}`;

# Memoization has a cost; use it when it solves a concrete problem.

Derive data during render when possible
// Prefer deriving directly:
const filtered = items.filter(item => item.active);

// Instead of syncing derived state in an effect.

# Avoid effects that only derive data from props/state.

Perform event-specific work in event handlers
function handleSave() {
  saveDraft(form);
}

<button onClick={handleSave}>Save</button>

# Do not move user-triggered logic into effects unnecessarily.

Recommended next

No recommendations yet.