React : UseState vs UseRef
With the introduction of functional components in React, state and lifecycle management has become much simpler than it ever was using class-based components. To have the same state, useState hook has provided the most easy-to-use implementation. But do we need useState in all scenarios because each state change causes a rerender of our application? Is there a faster alternative where we can have the same functionality to store values in cases where we don’t need a rerender? The answer to this is useRef hook.
What is useState?
UseState is a hook provided by React to allow the implementation of state in functional components. It returns an array with two values: the current value and the function to update it.
What is useRef?
UseRef is a hook provided by React that accepts an initial value and returns a reference with a property on it called ‘current’.
Eg: const currentRef = React.useRef(0); // console.log(currentRef)
These are generally used to minimize the rerender of components and are mainly used in form components by referencing the DOM elements.
Issues with useState:
The one major drawback of useState is the re-render of a component.
Let’s take a look at a basic example of a button click that generates a random number at each click.
If we click a button n number of times, the component is re-rendered for n times. This might not look too big of a problem for this scenario, but when we have a heavy component, each re-render cost will impact the application’s overall performance.
Another issue with using useState is that when we have to use the updated state value immediately after a change in the state value.
Let’s take the below example where we have a function that should return ‘5’ + the current state value and display it on the UI.
The setUpdatedNumber function should be updated with the current value of the number. Let’s go ahead and click twice on it.
We can see that on the first click, the console log had printed both of them as 0, but the ‘number’ should have been ‘5’, and the updated number should be ‘5’. We get the value for the first button click on the second click.
But why does this happen?
The setFunction for a useState hook is asynchronous in nature; hence it waits and executes in the background, and the setUpdatedNumber function never receives the current value of the number.
The answer to the current scenario will be the use of useRef hook.
Let’s take a look at the current example with useRef hook
With useRef hook, we have replaced the useState for number. As we can clearly see in generateNumber() function, we can update the value of number ref in real time(synchronously), and the values are correctly updated in the UI.
Limitations of useRef:
UseRefs are great for limiting the re-render of a component and help a lot when we are using forms in our application, but they do have a few limitations.
One of the major limitations is that the current value is not reflected directly on the UI.
The above example adds 5 to a number each time on button clicks. Let’s check if the UI also updates the value in real-time or not.
We can see that the value of number ref was updated on each button, but the UI did not reflect the update value. This is because there was no re-render to update the current UI.
Conclusion:
UseRefs are a great tool to help with optimizations, but their use case doesn’t cover all the benefits of a useState hook. A combination of both is required in an application to achieve optimal performance and stability. For more such updates, please subscribe to our blogs.