How useState made lazyness its feature?
Heard of lazy initialization?
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.