# 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 ( ); }; 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 ; }); ``` ## 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 ; } // 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 ( <> {state.count} ); } ``` ## 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