useState
Last updated
Was this helpful?
Last updated
Was this helpful?
The useState
hook looks incredibly cool in short examples, presentations or during an argument, however, in the vast majority of cases this is not the tool you want to use when managing state! Especially when dealing with event handlers there are too many pitfalls around useState
.
Instead, the tool you want to use is the hook which is based upon useState
but avoids the most significant issues.
If you want to use useState
directly, make sure to at least use the approach.
The useState
hook allows you to persistently store data between State Hook executions. It also provides a way to mutate the state.
Effectively, the useState
function accepts a value - the initial state - which will only be taken into consideration during its very first execution. It returns an array in which the first element represents the current value and the second element represents a mutator function, a function that can be used to change the value.
In this example, we've used the useState
hook, providing it with an initial value of false
and we've named the current value isSelected
and the mutator function is called setSelected
.
Thus, during the first execution of this Hook, the value of isSelected
will be false
(its initial value). But if, at some point, we invoke setSelected(true)
then any subsequent execution of this Hook will result in isSelected
having the value true
.
Sometimes it can be expensive to calculate an initial value. In these cases executing the calculation during every execution of the State Hook, just to discard the value after the very first run, would be wasteful. Thus, you can also provide a function as the initial value. It'll be evaluated during the first execution but ignored afterwards.
By passing a function which calculates the initial state, we avoid calculating the 15th fibonacci number for every execution of the function, thus significantly improving our performance.
Often you'll want to update a value in relation to the current value, especially when it comes to dealing with events. Thus, useState
allows you to specify an updater function which receives the current value and returns the new value.
This pattern is always better than the usual setCount(count + 1)
you'll see in marketing material as it eliminates a lot of potential issues consumers of your hook would other wise have. For example, if they start to optimise their code by wrapping the increaseCounter
within a useCallback
hook, they'd accidentally close over the old value of count, making it impossible to go beyond changing the original value by 1.
By following this approach you also get the opportunity to optimise your code to achieve better performance. Don't worry if you're not familiar with the other hooks used in this example, we'll look at them soon.
The unoptimised version of the hook was producing a lot of new functions during every single execution and because increaseCounter
and decreaseCounter
were bound to the current value of count, every usage of those functions had to be rebound during every execution as well. However, now that we are using updater functions and are no longer dependent on the current value of count, we can provide a meaningful name to the updater functions and move them out of the hook (saving 2 function creations per call) as well as use the useCallback
hook which will always return the very first version of the function defined for it, which effectively means that additional functions are easy to discard for the JavaScript VM since they're never really used.
Those adjustments result in a much better performance and a much more stable API for your hook.