---
name: react-tips
description: 10 high-impact React patterns and anti-patterns - state management, performance, hooks, and component design. Use when writing or reviewing React components.
---
# 10 React Tips That Actually Matter
Use these patterns when writing or reviewing React code. Each one prevents real bugs or eliminates unnecessary complexity.
## 1. Use useReducer When State Is Related
When multiple `useState` values depend on each other (loading + error + data), use `useReducer` instead. Prevents impossible state combinations where your UI lies to the user.
```javascript
// BAD: Three setters you can forget to coordinate
setIsLoading(false);
setError(null);
setPost(data);
// GOOD: One dispatch, one guaranteed valid state
dispatch({ type: 'FETCH_SUCCESS', payload: data });
```
**When to apply:** Any time changing one piece of state requires changing another.
## 2. useTransition Over Debounce
For search inputs and heavy filtering, use `useTransition` instead of debounce. It marks state updates as non-urgent so React can keep the UI responsive.
```javascript
const [isPending, startTransition] = useTransition();
startTransition(() => {
setFilteredItems(filterItems(query));
});
```
**When to apply:** Any input that triggers expensive re-renders (search, filters, large lists).
## 3. State Colocation
Move state as close as possible to where it's consumed. If only `SearchBox` and `SearchResults` need `searchTerm`, wrap them in a `SearchFeature` component that owns the state. Siblings won't re-render.
**When to apply:** Before reaching for `React.memo`, check if the state can just be moved down the tree.
## 4. useEffect Is Synchronization, Not Lifecycle
`useEffect` is NOT `componentDidMount`. It's "run this when these dependencies change." Don't use it for data fetching (use React Query/SWR). Don't put functions inside unless necessary. Extract logic out of the effect body.
**When to apply:** Any time you're writing a `useEffect`, ask: "Am I synchronizing with something external, or am I triggering logic?" If the latter, there's probably a better pattern.
## 5. Never Use Index as Key
`key={index}` causes state to stick to the wrong DOM nodes when items are added, removed, or reordered. Always use a stable, unique ID from your data (`key={item.id}`).
**When to apply:** Every list render. No exceptions.
## 6. Don't Overuse useMemo
`useMemo` has overhead: hook call + dependency comparison every render. For simple operations (string concat, basic math), the overhead exceeds the cost of just computing the value. Profile before memoizing.
```javascript
// BAD: Memoizing a string concatenation
const fullName = useMemo(() => `${first} ${last}`, [first, last]);
// GOOD: Just compute it
const fullName = `${first} ${last}`;
```
**When to apply:** Only use `useMemo` for genuinely expensive computations (large array operations, complex transformations). The React Compiler will handle the rest.
## 7. SRP = One Reason to Change
A component should have one reason to change, not "do one thing." Extract data-fetching into custom hooks. Keep presentation separate from logic. When the API changes, only the hook changes. When the layout changes, only the component changes.
**When to apply:** When a component mixes fetching, error handling, and rendering. Split into a hook + a presentational component.
## 8. Key Prop Resets Components
Use `key` on any component (not just lists) to force React to unmount and remount it. This resets all state and re-runs effects, eliminating dependency array complexity.
```javascript
```
**When to apply:** When a component's entire state depends on a single prop (user ID, tab ID, etc.).
## 9. useLayoutEffect for DOM Measurement
`useEffect` runs after the browser paints. `useLayoutEffect` runs before paint. Use `useLayoutEffect` when you need to measure DOM elements and immediately update styles to prevent one-frame flickers.
**When to apply:** Tooltips, popovers, dynamic positioning, any visual measurement + mutation.
## 10. Compound Components Pattern
Instead of passing config objects/arrays, build components that share state via Context. Each sub-component gets its own provider and reaches into the nearest parent's context.
```javascript
Title
Content
```
**When to apply:** Reusable UI components (accordions, tabs, menus, dropdowns) where the consumer needs flexibility in what goes inside.
## Quick Reference
| Problem | Reach For |
|---------|-----------|
| Related state getting out of sync | `useReducer` |
| UI lag on input | `useTransition` |
| Unnecessary re-renders | State colocation |
| Data fetching in useEffect | React Query / SWR |
| List rendering bugs | Stable `key` from data |
| Simple computation wrapped in useMemo | Remove the useMemo |
| Component with 4+ reasons to change | Custom hook + presentation split |
| Component state tied to a single ID | `key={id}` prop |
| DOM measurement flicker | `useLayoutEffect` |
| Rigid component APIs | Compound Components |