How To Use React useRef Hook

What is the `useRef` hook? How do you use it? When should you use `useRef` vs `useState`? What caveats should you be aware of when using `useRef`?

This hook is often a tricky one to get right but can be very powerful. Read on to learn how to `useRef` like a pro!

What is React’s useRef hook?

`useRef` is one of the standard hooks provided by React. It will return an object that you can use during the whole lifecycle of the component. 

The main use case for the `useRef` hook is to access a DOM child directly. I’ll show exactly how to do that in another section. 

Although accessing the DOM is the main use case, it doesn’t mean it’s the only one! `useRef` can also be very useful to hold a mutable value across different renders of your component. 

For example, it’s often quite handy when using external libraries that weren’t made with React in mind.

You can initialize a new ref inside a component with the following code:

// create a ref const yourRef = useRef();

You can optionally initialize it with a default value by passing it as an argument to the `useRef` hook:

// create a ref const yourRef = useRef('hello world');

Tip: `useRef` is a hook, and as such can only be used in functional components! To use refs in class components, you have `createRef` instead. I briefly show how to use `createRef` further down below.

How to use React useRef?

Once created, you can get and set the value of the ref by accessing the `.current` property of the object, like so:

// create a ref const exampleRef = useRef(); // set the ref value exampleRef.current = "Hello World"; // access the ref value: // this prints "Hello World" to the console console.log(exampleRef.current);

To access a DOM element, you create a ref, assign it to the DOM element you want to target using its `ref` attribute, then you can use it!

For example, say you want to get the height in pixels of a DOM element. To do this, you have to access the `offsetHeight` property of the DOM element. But how to get access to the DOM element? With a ref of course!

import { useEffect, useRef } from "react"; export default function App() { // create a ref const divElement = useRef(); // trigger on the first render of the component useEffect(() => { // get the height of the div element console.log( "The height of the div is: ", divElement.current.offsetHeight ); }, []); return ( <div ref={divElement}> <h1>Learn about useRef!</h1> </div> ); }

Tip: In the above example I’ve used `useEffect` to only call `divElement.current.offsetHeight` once the component was first rendered. Indeed, at first, the ref is `undefined`, and it’s only once the component renders and the div is created that it holds its DOM element value!

As you can see refs can be quite tricky to use, and you have to keep a few things in mind.

Caveats of using useRef

Some important things to keep in mind when using `useRef` are:

A ref changing value doesn’t trigger a re-render

This one is often a tricky one, and trips a lot of developers! It is the opposite behavior of what happens when using `useState`.

For example, the following code has a bug! Can you spot where it is?

import { useRef } from "react"; export default function App() { // create a ref const counter = useRef(0); // increase the counter by one const handleIncreaseCounter = () => { counter.current = counter.current + 1; }; return ( <div> <h1>Learn about useRef!</h1> <h2>Value: {counter.current}</h2> <button onClick={handleIncreaseCounter}> Increase counter </button> </div> ); }

Have you spotted it? If so, good job! The issue is that clicking the button increases the variable `counter` as expected, but it doesn’t trigger a re-render so we see nothing on the screen!

Tip: to learn how to use click handlers like the `handleIncreaseCounter`, check out this blog post!

It is useless to add a ref to a dependency array

Adding a ref to a dependency array (for example the one of a `useEffect` hook) will not trigger the callback! This is also a very common error. 

For example, in the following example, you can click on the button all you want and it won’t print anything to the console!

import { useEffect, useRef } from "react"; export default function App() { // create a ref const counter = useRef(0); // increase the counter by one const handleIncreaseCounter = () => { counter.curent = counter.current + 1; }; useEffect(() => { console.log("counter changed to: ", counter.current); }, [counter]); return ( <div> <h1>Learn about useRef!</h1> <h2>Value: {counter.current}</h2> <button onClick={handleIncreaseCounter}> Increase counter </button> </div> ); }

To fix both of these bugs, you should use `useState` instead of `useRef`:

import { useEffect, useState } from "react"; export default function App() { // create a counter const [counter, setCounter] = useState(0); // increase the counter by one const handleIncreaseCounter = () => { setCounter((previousCounter) => previousCounter + 1); }; useEffect(() => { console.log("counter changed to: ", counter); }, [counter]); return ( <div> <h1>Learn about useRef!</h1> <h2>Value: {counter}</h2> <button onClick={handleIncreaseCounter}> Increase counter </button> </div> ); }

Now it works!

Tip: in the above example, I’ve used the callback form of `useState`. You can learn more about it in this blog post.

When to avoid using useRef?

Most of the time, if you want to persist state across re-renders of your components you should be using `useState` instead of `useRef`. Defaulting to `useState`, and then only using `useRef` if you have a specific reason to do so is a good rule to code by!

Check out more info on `useState` on this blog post!

createRef vs useRef

`useRef` is the hook to create refs in functional components, but you can also use refs in your class components! The way you do it is by using the `createRef` function. 

The usage is very similar to `useRef`:

import { Component, createRef } from ‘react’; class YourComponent extends Component { constructor(props) { super(props); this.yourRef =createRef(); } render() { return <div ref={this.yourRef} />; } }

Wrap Up

I hope you now have a good understanding of what refs are and how to use them! 

Here is some good further reading if you want more material on refs and `useRef`:

👋 Hey, I'm Pierre Ouannes
I’m a Computer Science Engineer with an interest in Web development, Machine Learning and DevOps! I'm currently working as a Full Stack Engineer at Ellipsis Drive, mostly with React. Connect on LinkedIn or Github.

💬 Leave a comment

Your email address will not be published. Required fields are marked *

We will never share your email with anyone else.