Sign in
Log inSign up

How useState made lazyness its feature?

Heard of lazy initialization?

souvik roy's photo
souvik roy
·May 29, 2021·

3 min read

How useState made lazyness its feature?

How good would it be to get appreciated and valued for being lazy!. We can just imagine but useState is proving it that being lazy can be good sometimes (kind of reminds me of Cadbury 5star ad). Jokes apart let us know little about useState first. useState hook is a special function which takes one argument. The argument passed to useState is initial state value. It returns an array with two values. The first value is the initial value of the state variable and the second is a function (state dispatch function) which is used for updating state variable.

const [state, setState] = useState(initialstate)

Getting to the Point

const Counter = () => {
  const [count, setCount] = useState(0)
  const increment = () => setCount(count + 1)      //calling state dispatch function
  return <button onClick={increment}>{count}</button>
}

when you call the state dispatch function you pass a new value for the state and that causes re-render of the component which will again call useState and extract the new state value and dispatch the function again. But but but there is a problem here It is not considered a good practice. a good practice of calling a state would be the below line of code.

const [count, setCount] = useState(() => 0)      //useState is called with a function to return initial state
const increment = () => setCount(prev => prev + 1)     //dispatch function is called with a function

As you can see useState is called with a function to return initial state and dispatch function too is called with a function, which takes previous state value and returns a new one. Lets find out what differences it makes by not passing the initial state directly🤔.

useState Lazy initialisation

In the above example if you console log inside Counter function body, you will find out the function runs every time you click the button i.e., all code inside the function runs as well. Which means variables you pass are created and evaluated every render, which in this case is not a big deal for JavaScript engines. But...

What if the initial value for your state is computationally expensive like.. one mentioned below.

const initialState = window.localStorage.getItem('count')
const [count, setCount] = useState(initialState)        //for every render it is called.

Clearly in this case it is inefficient to run the initialState which is inside the function body every time there is a re-render of the component. The initialState is required only on the first render after that its value is not needed.

Here comes the lazy Initialization in to the picture. Once you provide useState with a function it solves the issue and provide good user experience.

const initialState = window.localStorage.getItem('count')
const [count, setCount] = useState(() => initialState)      //called only once initially Lazy initialization

Creating a function is fast, even if function is computationally expensive. So when a function is passed in useState, React will only call the function when it needs the initial value. This is what lazy Initialization is, its basically a performance optimization.

Conclusion

Lazy Initialization is a tactic of delaying the creation of value to an identifier or object until the first time it's needed. If the process is expensive we don't initialize it immediately to avoid lag on the user's experience. Then when it is needed by the user it is created.