When React Apps Become Sluggish
React's declarative model is productive, but carelessly passing inline objects or lifting state too high can cause massive component re-render cascades. When users type in an input box and notice a 150ms keystroke lag, the problem is almost always unnecessary re-renders.
1. State Colocation: Don't Put Everything in Global State
Developers often store local form inputs in global Redux or Zustand stores. Every single keystroke forces 40 unrelated components to re-render. Keep state as close to where it is used as possible:
// Bad: Global store tracking simple search input
const SearchBar = () => {
const { searchQuery, setSearchQuery } = useGlobalStore();
return <input value={searchQuery} onChange={(e) => setSearchQuery(e.target.value)} />;
};
// Good: Local state with debounced submission to parent
const SearchBar = ({ onSearch }) => {
const [localQuery, setLocalQuery] = useState("");
useEffect(() => {
const handler = setTimeout(() => onSearch(localQuery), 300);
return () => clearTimeout(handler);
}, [localQuery, onSearch]);
return <input value={localQuery} onChange={(e) => setLocalQuery(e.target.value)} />;
};2. Strategic Dynamic Imports (Route-Level Code Splitting)
Never force mobile users to download your entire 2MB bundle on the initial page load. Split heavy routes and modals using React.lazy() and Suspense:
const AdminDashboard = React.lazy(() => import("./pages/AdminDashboard"));
const AnalyticsModal = React.lazy(() => import("./components/AnalyticsModal"));In our audits at Korvith, route splitting routinely cuts initial JavaScript execution times by 65%.