React is a very cool library to use and build web apps with, and I am looking to better understand how React hooks work. In this article, I want to share what I have learnt about the useRef() hook to get you started using it in your own projects.
Prerequisites
- Basic understanding of React
- Basic understanding of the useState() hook
Introduction
Before diving into the nitty gritty stuff, it's important to note that React normally does not keep track of data stored in variables, so if for example we have a variable called count, and we keep incrementing the count, the changes will not reflect on the UI because react is not aware the count has changed
const App = () => {
let count = 0;
function increaseCount() {
count++;
}
};
return (
<>
<h2>Count: {count}</h2>
<button onClick={increaseCount}>Increment count</button>
</>
);
This is a problem because any data stored in variables will automatically be lost as soon as the application re-renders (when the state of the component updates). It's important to understand not all the data in your application needs to be stored in a state, sometimes you might just want to store a piece of information your application needs to function properly, but does not necessarily have anything to do with the UI, this is why we need a solution to help our component remember data we don't want to lose. This is what brought about the concept of the useRef() hook, it gives us the ability to store information in a React application without losing that information when the application re-renders.
What is useRef()?
useRef() is a built-in react hook that stores a reference to a piece of data you want your component to remember that does not affect the UI, this means any value stored in useRef() will not cause your component to re-render when it updates. Whenever our application re-renders, it is normally because the state of a component has changed, and when this happens, a new snapshot of the UI is generated. With this new snapshot, we get a new version of our component and as such, any value that was not previously tracked by React will be lost. Thanks to useRef(), we can store references to values so that even when our component re-renders, we can still access that value. useRef() returns a plain JavaScript object which has a current property used to access the reference value. Here is the syntax
{
current: initialValue;
}
Where initialValue can be any data type e.g a number, an array, a string etc.
Let's look at an example of how useRef() can help us retain information even after the application re-renders.
import { useState, useRef } from "react";
function RenderCounter() {
const [count, setCount] = useState(0);
const refCount = useRef(1);
// Increment the counter reference on every render
refCount.current += 1;
return (
<>
<p>Count: {count}</p>
<p>Component has rendered: {refCount.current} times</p>
<button onClick={() => setCount(count + 1)}>Increment Count</button>
</>
);
}
export default RenderCounter;
Whenever we click the Increment Count button, the component re-renders, but our refCount value does not reset to 1, rather it increments by 1. Now remember I said updates made to a reference does not cause your component to re-render, so in this example, you might mistakenly think because the reference is updating, that's why it is showing in the UI, but that's not true, rather it's because the state of the component is changing. If the state never updates, we won't see the updated refCount in the UI.
Interacting with DOM Elements
Apart from storing data you want your component to remember, you can also use useRef() to store references to specific DOM elements you want to access and interact with because in React, we don't use element selectors in vanilla JS like document.querySelector()
to target elements in the DOM as that will defeat the whole purpose of using React in the first place. Here is an example of how this is typically done
import { useRef } from "react";
function App() {
const inputRef = useRef(null);
return (
<>
<input ref={inputRef} />
</>
);
}
export default App;
When the component initially renders, we assign null to useRef() and pass it to a ref
attribute on the input element, this ref attribute allows us target a DOM element directly, and interact with it. After React renders our component, it updates the value of the reference to the DOM element which gives us access to properties and invoke methods available on that DOM element. If we want to focus on the input element when we click on a button, we can use the reference created and call the focus method on it.
import { useRef } from "react";
function App() {
const inputRef = useRef(null);
function focusInput() {
inputRef.current.focus();
}
return (
<>
<input ref={inputRef} />
<button onClick={focusInput}>Click me</button>
</>
);
}
export default App;
Caution!
Don't use useRef() to store the state of your application, only use it to store references to values you want to access when the component re-renders or to interact with DOM elements, basically anything that doesn't have to do with the UI but is required for the application to work properly is best kept in a useRef() hook. Since React is not aware of any changes made to a ref, if you store the state of your application in a reference, your application will behave strangely.
Conclusion
If you are familiar with the useState() hook, you know it has an updater function used to let React know when an update is made to the state, useRef() is basically just useState() without an updater function, that's why no update is sent to React whenever the reference updates because nothing triggers React to essentially React to that change.
That's all I have to share with you concerning the useRef() hook, how do you use the useRef() hook in your own web applications?, let me know. You can find out more about me on X, and check out some of my projects on Github
Top comments (0)