Boosting React app performance is crucial for a positive user experience. This article outlines seven proven performance patterns gleaned from optimizing numerous production React applications.
useMemo
and useCallback
:Problem: Unnecessary re-renders due to unchanged props or state.
Solution: Cache computationally expensive operations and function references.
<code class="language-javascript">const ExpensiveComponent = ({ items }) => { const sortedList = useMemo(() => items.sort((a, b) => a.price - b.price), [items]); const handleClick = useCallback(() => { console.log('Item clicked:', sortedList[0]); }, [sortedList]); return <ChildComponent onClick={handleClick} />; };</code>
Best Practices: Use with React.memo
for child components to prevent unnecessary subtree updates. Ideal for complex calculations (sorting, filtering), callbacks passed to optimized children, and stable context provider values.
Problem: Large initial bundle size impacting First Contentful Paint (FCP).
Solution: Dynamic imports and Suspense
for on-demand loading.
<code class="language-javascript">const HeavyChartLibrary = React.lazy(() => import('./ChartComponent')); const Dashboard = () => ( <React.Suspense fallback={<Spinner />}> {showCharts && <HeavyChartLibrary />} </React.Suspense> );</code>
Advanced: Integrate with React Router for route-based code splitting.
Problem: Rendering thousands of items overwhelms the DOM.
Solution: react-window
renders only visible items.
<code class="language-javascript">import { FixedSizeList } from 'react-window'; const BigList = ({ items }) => ( <FixedSizeList height={600} itemCount={items.length} itemSize={35} width="100%"> {({ index, style }) => ( <div style={style}>...</div> )} </FixedSizeList> );</code>
Bonus: Use VariableSizeList
for dynamic row heights and react-virtualized-auto-sizer
for responsive containers.
Problem: Multiple state updates causing cascading re-renders.
Solution: Leverage React 18's automatic batching.
React 18 :
<code class="language-javascript">setCount(1); setText('Updated'); // Single re-render</code>
Pre-React 18 or for complex scenarios: Use useReducer
for atomic state updates.
Problem: Excessive API requests from rapid user input (e.g., search bars).
Solution: A custom useDebounce
hook.
<code class="language-javascript">import { useEffect, useState } from 'react'; const useDebouncedValue = (value, delay) => { const [debouncedValue, setDebouncedValue] = useState(value); useEffect(() => { const handler = setTimeout(() => setDebouncedValue(value), delay); return () => clearTimeout(handler); }, [value, delay]); return debouncedValue; };</code>
Pro Tip: Combine with AbortController
to cancel pending requests.
Problem: Unnecessary re-renders of context consumers due to unrelated changes.
Solution: Split contexts and memoize provider values.
Problem: Slow UI due to waiting for API responses.
Solution: Provide immediate visual feedback and rollback on error.
Performance Checklist:
React.memo
, useMemo
, useCallback
strategically.Remember: Profile first, optimize second! These techniques are applicable across various React frameworks (Next.js, Gatsby, etc.).
The above is the detailed content of eact Performance Patterns Every Developer Should Steal (and How to Implement Them). For more information, please follow other related articles on the PHP Chinese website!