36

I am new to react Hooks. Am trying to make use of useState in my code. While I was using it I found a term "Lazy initial state"

https://reactjs.org/docs/hooks-reference.html#lazy-initial-state

const [state, setState] = useState(() => {
  const initialState = someExpensiveComputation(props);
  return initialState;
});

But I am not able to think of any use case where this lazy initialising of state will be useful.

Like say my DOM is rendering and it needs the state value, but my useState has not initialised it yet! And say if you have rendered the DOM and the someExpensiveComputation has finished, the DOM will re-render!

Victor
  • 3,669
  • 3
  • 37
  • 42
Peter
  • 1,069
  • 2
  • 13
  • 24
  • 2
    What puzzles me here is why `!!`? is `!` not enough? and what about humble `.`? – marzelin Oct 24 '19 at 11:13
  • 2
    Although the question has been answered I wanted to share this amazing blog post on [React's useState lazy initialization](https://kentcdodds.com/blog/use-state-lazy-initialization-and-function-updates) by Kent C. Dodds, you can refer this as well for better understanding. – Amit Mondal Apr 01 '21 at 08:12

1 Answers1

95

The value passed to the useState hook in the initial render is the initial state value, and gets disregarded in subsequent renders. This initial value can be the result of calling a function as in the following situation:

const Component = () => {
  const [state, setState] = useState(getInitialHundredItems())
}

But note that getInitialHundredItems is unconditionally and needlessly called on each render cycle.

For use cases like this instead of just calling a function that returns a value you can pass a function which returns the initial state. This function will only be executed once (initial render) and not on each render like the above code will. See Lazy Initial State for details.

const Component = () =>{
  const [state, setState] = useState(getInitialHundredItems)
}
Drew Reese
  • 165,259
  • 14
  • 153
  • 181
Dupocas
  • 20,285
  • 6
  • 38
  • 56
  • 1
    Well Explained!! Thanx, I understood it! – Peter Oct 24 '19 at 11:25
  • 1
    that could just be `useState(getInitialHundredItems)` right? – cryptojesus Jul 12 '20 at 18:37
  • Yeap! You can assume `react` does a comparison like `if(typeof initialValue === 'function') initialValue()`. Note that this is obviously pseudo code – Dupocas Jul 15 '20 at 14:19
  • 2
    "remember even though the initial value is disregarded upon next renders, the function which initializes it still gets called". What is the point of calling the function which initializes state in subsequent renders? Is the feature included in `react.js` for comparing state values for different renders? – nibble Jul 19 '20 at 18:18
  • A component is just a function which gets called on each render – Dupocas Jul 20 '20 at 00:44
  • You can shorten it even more: `const [state, setState] = useState(getInitialHundredItems)` – lata Oct 14 '20 at 15:14
  • 2
    Yeap. But for demonstration's purposes `() => func()` is easier to understand – Dupocas Oct 21 '20 at 13:07
  • @lata Agree, but this is possible only if the function exists already. Most examples I've seen don't need a named function and look more elegant using the other form (at least there is less noise). Nothing wrong with one or the other, though, as these are stylistic things and are heavily subjective. :-) – ankush981 Jan 02 '21 at 07:51
  • 2
    @Dupocas, "remember even though the initial value is disregarded upon next renders, the function which initializes it still gets called" - is this mentioned in official docs? I could not locate it if yes. – Abhinandan Khilari Jul 12 '21 at 18:41
  • Right [here](https://reactjs.org/docs/hooks-reference.html#lazy-initial-state) @AbhinandanKhilari – Dupocas Jul 12 '21 at 18:48
  • 1
    @Dupocas, thanks but all it says is "In subsequent renders, initialState is disregarded". But it doesn't say like - "the function which initializes it still gets called". Am I missing something here? – Abhinandan Khilari Jul 12 '21 at 20:38
  • Is it possible to lazy initialize multiple states with the same function. So that it would be called only once – Noname Oct 27 '21 at 11:21
  • Could you elaborate? – Dupocas Oct 28 '21 at 12:38
  • I'm going to attempt a rephrased elaboration, to state it in the way of understanding that helped clarify it for myself: if useState(param), where param is a function call to determine the param (like useState(getValue()), that means the function is called each re-render to resolve the param that gets passed to useState(); whereas if param is itself a function (like useState(getValue), useState receives the function itself as the param, and calls the function itself, and will therefore know not to call it on all subsequent re-renders. Essentially what Dupocas said, but elaborated. – GG2 Feb 05 '22 at 01:53
  • Whereas, the React docs are unclear; and Kent Dodd's example (referenced above) was still unclear, because he extracted out the function and called it separately outside of useState(...), i.e. `x = callMe(); useState(x);` so, duh, of course callMe() will get called on each re-render; whereas it is not explicitly clear that, aha! duh, callMe() in `useState(callMe())` will also be executed on each re-render, because it has to in order to resolve the parameter that gets passed to useState(), before actually calling useState(). – GG2 Feb 05 '22 at 01:59
  • @Dupocas The lazy initialization function is only called on the initial render. Perhaps the docs have been updated since your [comment](https://stackoverflow.com/questions/58539813/lazy-initial-state-what-it-is-and-how-to-use-it#comment120802159_58539958), but the docs make it overtly clear now: "In subsequent renders, it is disregarded. If the initial state is the result of an expensive computation, you may provide a function instead, which will be ***executed only on the initial render***" (*emphasis mine*). It is not called needlessly each render; it wouldn't make any sense to do so. – Drew Reese Jan 21 '23 at 06:32
  • Yeap, thanks for pointing this out @DrewReese back in 2019 the docs didn't mentioned lazy initial state at all. I'll update the answer with a link to the official docs. My point was that if not a function the state initializator would be invoked on each render cause it's just cheaper to recreate the object instead of modifying the underlying component, but in cases where this initialization is expensive the function approach would stop that initial state from being recreated by memoizing the result from the invoked initial function. – Dupocas Jan 23 '23 at 12:12
  • 1
    @Dupocas Sorry, I had to reread your answer again a few times to realize you are pointing out a hypothetical scenario where ***a*** function that computes ***an*** initial value is ***needlessly*** directly called each render cycle ***because*** it's ***not*** a lazy initialization function. I thought your middle sentence was stating that the lazy initializer was going to be called each cycle. – Drew Reese Jan 23 '23 at 17:32
  • Thanks for the editing, it's much clearer now – Dupocas Jan 23 '23 at 17:54