# React Patterns & Best Practices
**Category**: development
**Purpose**: Modern React patterns, hooks usage, and component design principles
**Used by**: frontend-specialist
---
## Overview
This guide covers modern React patterns using functional components, hooks, and best practices for building scalable React applications.
## Component Patterns
### 1. Functional Components with Hooks
**Always use functional components**:
```jsx
// Good
function UserProfile({ userId }) {
const [user, setUser] = useState(null);
useEffect(() => {
fetchUser(userId).then(setUser);
}, [userId]);
return
{user?.name}
;
}
```
### 2. Custom Hooks for Reusable Logic
**Extract common logic into custom hooks**:
```jsx
// Custom hook
function useUser(userId) {
const [user, setUser] = useState(null);
const [loading, setLoading] = useState(true);
const [error, setError] = useState(null);
useEffect(() => {
setLoading(true);
fetchUser(userId)
.then(setUser)
.catch(setError)
.finally(() => setLoading(false));
}, [userId]);
return { user, loading, error };
}
// Usage
function UserProfile({ userId }) {
const { user, loading, error } = useUser(userId);
if (loading) return ;
if (error) return ;
return {user.name}
;
}
```
### 3. Composition Over Props Drilling
**Use composition to avoid prop drilling**:
```jsx
// Bad - Props drilling
function App() {
const [theme, setTheme] = useState('light');
return ;
}
// Good - Composition with Context
const ThemeContext = createContext();
function App() {
const [theme, setTheme] = useState('light');
return (
);
}
function Layout() {
const { theme } = useContext(ThemeContext);
return ...
;
}
```
### 4. Compound Components
**For complex, related components**:
```jsx
function Tabs({ children }) {
const [activeTab, setActiveTab] = useState(0);
return (
{children}
);
}
Tabs.List = function TabsList({ children }) {
return {children}
;
};
Tabs.Tab = function Tab({ index, children }) {
const { activeTab, setActiveTab } = useContext(TabsContext);
return (
setActiveTab(index)}
>
{children}
);
};
Tabs.Panel = function TabPanel({ index, children }) {
const { activeTab } = useContext(TabsContext);
return activeTab === index ? {children}
: null;
};
// Usage
Tab 1
Tab 2
Content 1
Content 2
```
## Hooks Best Practices
### 1. useEffect Dependencies
**Always specify dependencies correctly**:
```jsx
// Bad - Missing dependencies
useEffect(() => {
fetchData(userId);
}, []);
// Good - Correct dependencies
useEffect(() => {
fetchData(userId);
}, [userId]);
// Good - Stable function reference
const fetchData = useCallback((id) => {
api.getUser(id).then(setUser);
}, []);
useEffect(() => {
fetchData(userId);
}, [userId, fetchData]);
```
### 2. useMemo for Expensive Calculations
**Memoize expensive computations**:
```jsx
function DataTable({ data, filters }) {
const filteredData = useMemo(() => {
return data.filter(item =>
filters.every(filter => filter(item))
);
}, [data, filters]);
return ;
}
```
### 3. useCallback for Stable References
**Prevent unnecessary re-renders**:
```jsx
function Parent() {
const [count, setCount] = useState(0);
// Bad - New function on every render
const handleClick = () => setCount(c => c + 1);
// Good - Stable function reference
const handleClick = useCallback(() => {
setCount(c => c + 1);
}, []);
return ;
}
const Child = memo(function Child({ onClick }) {
return Click ;
});
```
## State Management Patterns
### 1. Local State First
**Start with local state, lift when needed**:
```jsx
// Local state
function Counter() {
const [count, setCount] = useState(0);
return setCount(c => c + 1)}>{count} ;
}
// Lifted state when shared
function App() {
const [count, setCount] = useState(0);
return (
<>
>
);
}
```
### 2. useReducer for Complex State
**Use reducer for related state updates**:
```jsx
const initialState = { count: 0, step: 1 };
function reducer(state, action) {
switch (action.type) {
case 'increment':
return { ...state, count: state.count + state.step };
case 'decrement':
return { ...state, count: state.count - state.step };
case 'setStep':
return { ...state, step: action.payload };
default:
return state;
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, initialState);
return (
<>
dispatch({ type: 'decrement' })}>-
{state.count}
dispatch({ type: 'increment' })}>+
>
);
}
```
## Performance Optimization
### 1. Code Splitting
**Lazy load routes and heavy components**:
```jsx
import { lazy, Suspense } from 'react';
const Dashboard = lazy(() => import('./Dashboard'));
const Settings = lazy(() => import('./Settings'));
function App() {
return (
}>
} />
} />
);
}
```
### 2. Virtualization for Long Lists
**Use virtualization for large datasets**:
```jsx
import { FixedSizeList } from 'react-window';
function VirtualList({ items }) {
const Row = ({ index, style }) => (
{items[index].name}
);
return (
{Row}
);
}
```
## Best Practices
1. **Keep components small and focused** - Single responsibility principle
2. **Use TypeScript** - Type safety prevents bugs and improves DX
3. **Colocate related code** - Keep components, styles, and tests together
4. **Use meaningful prop names** - Clear, descriptive names improve readability
5. **Avoid inline functions in JSX** - Extract to named functions or useCallback
6. **Use fragments** - Avoid unnecessary wrapper divs
7. **Handle loading and error states** - Always show feedback to users
8. **Test components** - Use React Testing Library for user-centric tests
## Anti-Patterns
- ❌ **Prop drilling** - Use context or composition instead
- ❌ **Massive components** - Break down into smaller, focused components
- ❌ **Mutating state directly** - Always use setState or dispatch
- ❌ **Using index as key** - Use stable, unique identifiers
- ❌ **Unnecessary useEffect** - Derive state when possible
- ❌ **Ignoring ESLint warnings** - React hooks rules prevent bugs
- ❌ **Not memoizing context values** - Causes unnecessary re-renders
## References
- React Documentation (react.dev)
- React Patterns by Kent C. Dodds
- Epic React by Kent C. Dodds