React's rendering process is powerful but can become inefficient when components re-render without meaningful changes.
Let's explore strategies to prevent these unnecessary renders.
Understanding the Problem
React components typically re-render in three scenarios:
- If the state changes
- If the props change
- Parent component re-renders
The last scenario can lead to wasted renders when child components don't actually need updating:
Let's take a look at an example of this scenario:
function ParentComponent() {
const [count, setCount] = useState(0);
return (
<div>
<button onClick={() => setCount(count + 1)}>
Clicked {count} times
</button>
<ChildComponent /> {/* Re-renders on every click despite no prop changes */}
</div>
);
}
React.memo for Function Components
Wrap function components with React.memo() to skip renders when props haven't changed:
const ChildComponent = React.memo(function ChildComponent() {
console.log("Child rendered!");
return <div>I'm a memoized component</div>;
});
// Now ChildComponent only re-renders when its props change
shouldComponentUpdate for Class Components
For class components, implement shouldComponentUpdate():
class ListItem extends React.Component {
shouldComponentUpdate(nextProps) {
// Only re-render if the item data changed
return nextProps.item.id !== this.props.item.id ||
nextProps.item.content !== this.props.item.content;
}
render() {
return <div>{this.props.item.content}</div>;
}
}
useMemo and useCallback Hooks
Prevent recreating objects and functions on each render:
function SearchComponent({ data }) {
const [query, setQuery] = useState("");
// Without useMemo, filteredData would be recalculated on every render
const filteredData = useMemo(() => {
return data.filter(item => item.name.includes(query));
}, [data, query]); // Only recalculate when data or query changes
// Prevent handleClick from being recreated on every render
const handleClick = useCallback(() => {
console.log("Button clicked!");
}, []); // Empty dependency array means this function never changes
return (
<div>
<input value={query} onChange={e => setQuery(e.target.value)} />
<button onClick={handleClick}>Search</button>
<DataList data={filteredData} />
</div>
);
}
By implementing these techniques, you'll significantly reduce unnecessary renders and improve your React application's performance!
Stay Sharp. Weekly Insights.
New posts, framework updates and weekly software conversations.
No spam. Unsubscribe anytime.
Walt is a software engineer, startup founder and previous mentor for a coding bootcamp. He has been creating software for the past 20+ years.