Exploring useRef vs useState in React: A Comprehensive Comparison

Rishabh Srivastava
5 min readAug 18, 2023

--

React is a really popular tool that developers use to build things on the web. It’s like a big box of tools, and one of the tools it has is called “hooks”. Two important hooks in React are called useRef and useState. Even though they might seem a bit alike, they actually do different things.

Think of it like this: Imagine you have a toolbox with a special wrench and a special screwdriver. They might look a bit similar, but they each do their own special job. That’s kinda like useRef and useState in React.

So, in this article, we’re going to talk about useRef and useState. We’ll show you examples so you can understand better. You’ll see that useRef is good for certain things, and useState is good for different things. It’s a bit like comparing a flashlight to a computer mouse — they’re both helpful tools, but for different tasks.

By the end, you’ll know when to use useRef and when to use useState. This will help you build cool things with React more easily!

Understanding useRef: In the realm of React, the useRef hook takes center stage by furnishing a mutable reference that withstands the tides of component renders. Diverging from useState, which orchestrates state and triggers re-renders, useRef primarily empowers interactions with the DOM or accommodates mutable values that refrain from triggering re-renders. Its outcome is a mutable object housing a ‘current’ property.

Example 1: Harnessing DOM Elements

Consider a scenario where triggering the focus on an input field hinges upon a button click. Through useRef, this objective becomes attainable:

import React, { useRef } from 'react';

function MyComponent() {
const inputRef = useRef(null);

const handleClick = () => {
inputRef.current.focus();
};

return (
<div>
<input ref={inputRef} />
<button onClick={handleClick}>Focus Input</button>
</div>
);
}

In this instance, a ref is instantiated via useRef and linked to the inputRef variable. inputRef is then passed to the ‘ref’ attribute of the input element, thereby permitting access to the input’s DOM node. Upon button click, execution of the handleClick function culminates in inputRef.current.focus(), spotlighting the input field.

Understanding useState: Counterpoising the useRef, the useState hook emerges as the architect of state management within functional components. This hook facilitates the creation of variables amenable to updates, which in turn stimulate re-renders upon value alterations. The useState hook dispenses an array comprising the current state value and a function for its modification.

Example 2: Taming a Counter

Envisage a modest counter component materializing through the agency of useState:

import React, { useState } from 'react';
function Counter() {
const [count, setCount] = useState(0);
const increment = () => {
setCount(count + 1);
};
return (
<div>
<p>Count: {count}</p>
<button onClick={increment}>Increment</button>
</div>
);
}

In the preceding code, array destructuring ushers in the count state variable and the setCount function for its manipulation. The initial value of count is initialized as 0 via useState(0). As the button garners clicks, execution of the increment function appends 1 to the count state, subsequently inciting component re-renders to reflect the revised count value.

Comparative Analysis of useRef and useState: Engaging in a side-by-side analysis of useRef and useState reveals their distinctive roles:

State Management:

useState: The quintessence of useState is state management within a component. Its hallmark is the triggering of re-renders following state modifications, ensuring a UI congruent with the latest data.

useRef: Here, useRef eschews state management, instead accentuating DOM interaction or storage of mutable values. Re-renders are not evoked by updates to the current property of a useRef-created reference.

DOM Interaction and Storage:

useState: In the domain of DOM interaction, useState takes a back seat. Its prime forte remains state control.

useRef: Conversely, useRef is the tool of choice for DOM interactions like targeting input values, focusing elements, or dimension assessments. This hook establishes references to DOM nodes, permitting retrieval of their attributes sans re-renders.

Persistence Across Renders:

useState: Every component render begets a fresh initialization of state through useState.

useRef: Here, the constancy of value across component renders shines forth, a feat achieved by useRef.

Re-render Dynamics:

useState: Refreshing the value returned by useState propels component re-renders.

useRef: Updating the current property of a useRef-forged reference shirks re-renders.

Use Cases Unveiled: In delving deeper, the practical employment scenarios of useRef and useState come into focus:

useRef — Aiding Accessibility and Storage:

1.1 Accessing DOM Elements: Navigating and modifying DOM elements such as focusing inputs, scrolling to designated zones, or measuring dimensions, demands the deployment of useRef.

1.2. Storing Mutable Values: For values necessitating permanence across renders without influencing UI or inciting re-renders, useRef is the answer. It’s apt for caching, value comparison, or preserving mutable data.

useState — Sculpting UI and Handling Interaction:

2.1. Managing Component State: The province of useState is the orchestration and evolution of state triggering re-renders. This makes it indispensable for crafting UI dynamics.
2.2. User Interaction Orchestration: useState finds its calling in managing interactive elements like checkboxes, toggles, or input fields. The UI adjusts in response to user input.

Illustrative Example: To elucidate the divergence, consider a situation where both useRef and useState can contribute:

Scenario: Crafting a form consisting of an input field and a submit button. On clicking the submit button, a success message must surface without erasing the input field’s content.

Using useRef:

import React, { useRef } from 'react';
function Form() {
const inputRef = useRef(null);
const handleSubmit = () => {
const value = inputRef.current.value;
// Form submission
displaySuccessMessage();
};
const displaySuccessMessage = () => {
// Display success message without clearing input field
};
return (
<div>
<input ref={inputRef} />
<button onClick={handleSubmit}>Submit</button>
</div>
);
}

In this instance, useRef empowers the creation of an input field reference. Upon the submit button’s activation, the input’s value is accessed using inputRef.current.value, facilitating form submission sans a UI re-render.

Using useState:

import React, { useState } from 'react';

function Form() {
const [inputValue, setInputValue] = useState('');
const handleSubmit = () => {
// Form submission
displaySuccessMessage();
};
const displaySuccessMessage = () => {
// Display success message
setInputValue(''); // Clear input field
};
const handleInputChange = (e) => {
setInputValue(e.target.value);
};
return (
<div>
<input value={inputValue} onChange={handleInputChange} />
<button onClick={handleSubmit}>Submit</button>
</div>
);
}

In this rendition, useState governs the input field’s state. Aided by the handleInputChange function, user input causes re-renders for state update reflection. On submitting, the displaySuccessMessage function not only exhibits the success message but also triggers the setInputValue function, effectively clearing the input field.

In summation, the tale of useRef and useState unveils their discrete domains of influence. While useRef is the sentinel for DOM interactions and value storage sans re-renders, useState dons the mantle of UI orchestration and state management. By grasping their differences and astutely selecting between the two, React aficionados can manifest potent, performant, and engaging applications. Your journey through this article is deeply appreciated, and we welcome your feedback and inquiries in the comments section. Your insights drive our growth.

Author: Rishabh Srivastava

Contact: Email: rishabhsri73@gmail.com

LinkedIn: Rishabh

--

--

No responses yet