| 1 | --- |
| 2 | title: Use Lazy State Initialization |
| 3 | impact: MEDIUM |
| 4 | impactDescription: wasted computation on every render |
| 5 | tags: react, hooks, useState, performance, initialization |
| 6 | --- |
| 7 | |
| 8 | ## Use Lazy State Initialization |
| 9 | |
| 10 | Pass a function to `useState` for expensive initial values. Without the function form, the initializer runs on every render even though the value is only used once. |
| 11 | |
| 12 | **Incorrect (runs on every render):** |
| 13 | |
| 14 | ```tsx |
| 15 | function FilteredList({ items }: { items: Item[] }) { |
| 16 | // buildSearchIndex() runs on EVERY render, even after initialization |
| 17 | const [searchIndex, setSearchIndex] = useState(buildSearchIndex(items)) |
| 18 | const [query, setQuery] = useState('') |
| 19 | |
| 20 | // When query changes, buildSearchIndex runs again unnecessarily |
| 21 | return <SearchResults index={searchIndex} query={query} /> |
| 22 | } |
| 23 | |
| 24 | function UserProfile() { |
| 25 | // JSON.parse runs on every render |
| 26 | const [settings, setSettings] = useState( |
| 27 | JSON.parse(localStorage.getItem('settings') || '{}') |
| 28 | ) |
| 29 | |
| 30 | return <SettingsForm settings={settings} onChange={setSettings} /> |
| 31 | } |
| 32 | ``` |
| 33 | |
| 34 | **Correct (runs only once):** |
| 35 | |
| 36 | ```tsx |
| 37 | function FilteredList({ items }: { items: Item[] }) { |
| 38 | // buildSearchIndex() runs ONLY on initial render |
| 39 | const [searchIndex, setSearchIndex] = useState(() => buildSearchIndex(items)) |
| 40 | const [query, setQuery] = useState('') |
| 41 | |
| 42 | return <SearchResults index={searchIndex} query={query} /> |
| 43 | } |
| 44 | |
| 45 | function UserProfile() { |
| 46 | // JSON.parse runs only on initial render |
| 47 | const [settings, setSettings] = useState(() => { |
| 48 | const stored = localStorage.getItem('settings') |
| 49 | return stored ? JSON.parse(stored) : {} |
| 50 | }) |
| 51 | |
| 52 | return <SettingsForm settings={settings} onChange={setSettings} /> |
| 53 | } |
| 54 | ``` |
| 55 | |
| 56 | Use lazy initialization when computing initial values from localStorage/sessionStorage, building data structures (indexes, maps), reading from the DOM, or performing heavy transformations. |
| 57 | |
| 58 | For simple primitives (`useState(0)`), direct references (`useState(props.value)`), or cheap literals (`useState({})`), the function form is unnecessary. |
| 59 |