| 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 |
| 16 | // buildSearchIndex() runs on EVERY render, even after initialization |
| 17 | const [searchIndex, |
| 18 | const [query, |
| 19 | |
| 20 | // When query changes, buildSearchIndex runs again unnecessarily |
| 21 | return <SearchResults |
| 22 | } |
| 23 | |
| 24 | function UserProfile() { |
| 25 | // JSON.parse runs on every render |
| 26 | const [settings, |
| 27 | |
| 28 | return <SettingsForm |
| 29 | } |
| 30 | ``` |
| 31 | |
| 32 | **Correct (runs only once):** |
| 33 | |
| 34 | ```tsx |
| 35 | function FilteredList({ items |
| 36 | // buildSearchIndex() runs ONLY on initial render |
| 37 | const [searchIndex, |
| 38 | const [query, |
| 39 | |
| 40 | return <SearchResults |
| 41 | } |
| 42 | |
| 43 | function UserProfile() { |
| 44 | // JSON.parse runs only on initial render |
| 45 | const [settings, |
| 46 | const stored = |
| 47 | return stored ? |
| 48 | }); |
| 49 | |
| 50 | return <SettingsForm |
| 51 | } |
| 52 | ``` |
| 53 | |
| 54 | Use lazy initialization when computing initial values from localStorage/sessionStorage, building data structures (indexes, maps), reading from the DOM, or performing heavy transformations. |
| 55 | |
| 56 | For simple primitives (`useState(0)`), direct references (`useState(props.value)`), or cheap literals ( |