noctcore-react/prefer-lazy-state-init
Wrap an expensive
useStateinitializer call in a lazy function so it runs once, not every render.
Recommended preset: error · Autofix: yes · Suggestions: no · Type information: not needed
🔧 This rule is automatically fixable.
useState(expensiveCall()) evaluates its initializer on every render. React only keeps the
first result, so every render after the first pays the cost for nothing. Wrapping the initializer in
a function — useState(() => expensiveCall()) — makes React call it once, lazily, on mount.
What it flags
Section titled “What it flags”A useState call (or React.useState) whose first argument is a call expression whose callee
path is listed in initializers. By default that is JSON.parse, localStorage.getItem, and
sessionStorage.getItem. A callee is matched by its dotted path (localStorage.getItem) or bare
name (buildInitialState).
// runs JSON.parse on every renderconst [state, setState] = useState(JSON.parse(raw));// lazy: runs once on mountconst [state, setState] = useState(() => JSON.parse(raw));Autofix
Section titled “Autofix”The autofix wraps the argument in () => ....
What it does not flag
Section titled “What it does not flag”Anything already wrapped in a function is left alone. So are initializers that are not a listed
call: a literal (useState(0)), an identifier or member access (useState(props.initial)), and a
call whose callee is not in initializers (useState(compute())).
Options
Section titled “Options”| Option | Type | Default | Meaning |
|---|---|---|---|
initializers |
string[] |
['JSON.parse', 'localStorage.getItem', 'sessionStorage.getItem'] |
Callee paths whose call in a useState initializer must be made lazy. Add your own expensive builders. |
'noctcore-react/prefer-lazy-state-init': ['error', { initializers: ['JSON.parse', 'crypto.randomUUID', 'buildInitialState'],}]When not to use it
Section titled “When not to use it”If your initializers list only contains cheap calls, lazy init adds noise for no benefit — narrow
the list or disable the rule.