![]()
Optimizing render performance is crucial for building smooth React applications. Here are the most effective techniques to prevent unnecessary re-renders:
1. React.memo for Component Memoization
const MyComponent = React.memo(function MyComponent(props) {
/* render using props */
});
// Only re-renders if props change
When to use:
- Pure functional components
- Components that render often with the same props
- Components whose parents re-render frequently
2. useMemo for Expensive Calculations
const memoizedValue = useMemo(() => computeExpensiveValue(a, b), [a, b]);
When to use:
- Complex calculations in render
- Derived data that doesn’t change often
- Preventing child component re-renders when passing objects/arrays
3. useCallback for Function References
const memoizedCallback = useCallback(() => {
doSomething(a, b);
}, [a, b]);
When to use:
- Passing callbacks to optimized child components
- Functions in dependency arrays of other hooks
- Event handlers that shouldn’t change between renders
4. Proper State Management
Component state:
const [state, setState] = useState(initialState);
// Use functional updates when new state depends on previous
setState(prev => prev + 1);
Context optimization:
// Split contexts to avoid unnecessary updates
const UserContext = createContext();
const SettingsContext = createContext();
// Or use selectors with useContextSelector
5. Key Prop Optimization
// Use stable keys for list items
{items.map(item => (
<ListItem key={item.id} item={item} />
))}
// Avoid array indices as keys when list changes
6. ShouldComponentUpdate (Class Components)
class MyComponent extends React.Component {
shouldComponentUpdate(nextProps, nextState) {
// Only re-render if specific props/state change
return this.props.value !== nextProps.value;
}
}
7. Children Prop Pitfalls
// This causes children to re-render:
<ExpensiveComponent>
<Child />
</ExpensiveComponent>
// Better: Move children as props
<ExpensiveComponent child={<Child />} />
8. State Colocation
// Move state down to the components that need it
// Instead of:
function Parent() {
const [state, setState] = useState();
return (
<>
<ChildA state={state} />
<ChildB setState={setState} />
</>
);
}
// Do:
function Parent() {
return (
<>
<ChildA />
<ChildB />
</>
);
}
9. Avoiding Inline Objects/Functions
// Bad - creates new object each render
<Component style={{ color: 'red' }} />
// Good - memoize styles
const styles = useMemo(() => ({ color: 'red' }), []);
<Component style={styles} />
10. Virtualization for Large Lists
// Use react-window or react-virtualized for long lists
import { FixedSizeList as List } from 'react-window';
Debugging Re-renders
Use these tools to identify unnecessary renders:
- React DevTools Profiler
why-did-you-renderlibrary- Custom hook:
function useWhyDidYouUpdate(name, props) {
const previousProps = useRef();
useEffect(() => {
if (previousProps.current) {
const changes = {};
Object.keys({ ...previousProps.current, ...props }).forEach(key => {
if (previousProps.current[key] !== props[key]) {
changes[key] = {
from: previousProps.current[key],
to: props[key]
};
}
});
if (Object.keys(changes).length) {
console.log('[why-did-you-update]', name, changes);
}
}
previousProps.current = props;
});
}
When to Optimize
Don’t prematurely optimize – only apply these techniques when:
- You notice performance issues
- Profiling shows unnecessary re-renders
- Components render frequently with the same props
- Working with large lists or complex UIs
Remember that React is generally fast enough for most use cases without these optimizations. Always measure before and after applying optimizations to verify they help.
