hardFrontend EngineerSaaS
How would you optimize a React component that re-renders unnecessarily when parent state changes?
Posted 18/04/2026
by Mehedy Hasan Ador
Question Details
At a SaaS company interview:
> "Our dashboard has a sidebar with navigation and a main content area. When the user types in a search input (in the header), the entire sidebar re-renders on every keystroke, causing visible lag. The sidebar has 50+ navigation items. How would you fix this?"
> "Our dashboard has a sidebar with navigation and a main content area. When the user types in a search input (in the header), the entire sidebar re-renders on every keystroke, causing visible lag. The sidebar has 50+ navigation items. How would you fix this?"
Suggested Solution
The Problem: Unnecessary Re-renders
function Dashboard() {
const [search, setSearch] = useState('');
// Every keystroke → Dashboard re-renders → Sidebar re-renders
return (
<div>
<Header search={search} onSearchChange={setSearch} />
<Sidebar /> {/* Re-renders on every keystroke! */}
<MainContent search={search} />
</div>
);
}
Solutions (Ranked by Impact)
1. React.memo — Prevent Re-renders
const Sidebar = React.memo(function Sidebar() {
return <nav>{/* 50+ items */}</nav>;
});
// Now only re-renders if props change (no props = no re-render)
2. useMemo — Memoize Expensive Computations
const filteredItems = useMemo(
() => navItems.filter(item => item.label.includes(search)),
[navItems, search]
);
// Only recalculates when dependencies change
3. useCallback — Stable Function References
const handleClick = useCallback((id) => {
setSelected(id);
}, []); // Stable reference across renders
<Sidebar onItemClick={handleClick} />
4. Move State Down — Colocation
// BEFORE: Search state in parent → everything re-renders
function Dashboard() {
const [search, setSearch] = useState('');
return (
<div>
<Header search={search} onSearchChange={setSearch} />
<Sidebar />
</div>
);
}
// AFTER: Search state in Header only
function Dashboard() {
return (
<div>
<Header /> {/* Search state lives here now */}
<Sidebar /> {/* Never re-renders on search */}
</div>
);
}
5. useDeferredValue — Concurrent Feature (React 18+)
function Dashboard() {
const [search, setSearch] = useState('');
const deferredSearch = useDeferredValue(search);
return (
<div>
<input value={search} onChange={e => setSearch(e.target.value)} />
<MainContent search={deferredSearch} /> {/* Deferred, non-blocking */}
</div>
);
}
Decision Tree
Is the component receiving props it doesn't use?
→ Move state down or lift state up
Is the component expensive to render with same props?
→ React.memo
Is there an expensive computation on every render?
→ useMemo
Are callback functions causing child re-renders?
→ useCallback
Is typing/input laggy because of heavy rendering?
→ useDeferredValue or move state down
Profiling in Production
React DevTools Profiler shows:
- Which components re-rendered
- Why they re-rendered (props changed? parent rendered?)
- How long each render took