WittCode💻

React useRef Hook

By

Learn how to use the useRef React hook, when to use the useRef hook, how useRef can increase a React application's efficiency, and useState vs useRef.

Table of Contents 📖

What is the useRef Hook?

The useRef hook is a React hook that stores a value. When this value is updated it does not cause a re-render. This is different from the useState hook which causes a re-render when its value changes. The useRef hook can also be used to access and work with the DOM.

useRef Hook and Mutable Values

To use the useRef hook, import it from the react library.

import { useRef } from "react";

const App = () => { return

My App
}

export default App;

The useRef hook takes an initial value and returns an object with the key current, whose value is the provided initial value.

import { useRef } from "react";

const App = () => { const count = useRef(0); console.log(count); // { current: 0 } const value = count.current; console.log(value); // 0 return

My App
}

export default App;

Here, we provide the useRef hook an initial value of 0 and assign it to a variable called count. When printing the count variable, we can see an object with the key current and the value 0. If no initial value is provided, then the current key is given the value undefined.

import { useRef } from "react";

const App = () => { const count = useRef(0); const myUndefined = useRef(); console.log(count); // { current: 0 } console.log(myUndefined); // { current: undefined } const value = count.current; console.log(value); // 0 return

My App
}

export default App;

Here, the variable myUndefined is given no initial value and thus useRef returns an object with the key current and the value undefined.

useRef Hook and Re-rendering

Specifically, what useRef returns is a reference. When this reference is updated, the component is not re-rendered. To demonstrate this, lets create a button that increments the count reference when clicked.

import { useRef } from "react";

const App = () => { const count = useRef(0);

const increment = () => {
    count.current++;
    // The value increases
    console.log(`The count is: ${count.current}`);
}

// The value displayed on the button does not change
return <button onClick={increment}>The count is {count.current}</button>

}

export default App;

Here, the new count value is logged to the console. However, the new count value is not displayed on the UI as no re-rendering occurs. In other words, the button returned from the App component is not rendered again. However, even when the component does re-render the value from useRef is persisted. To cause our component to re-render, lets add state to it and change it. When a component's state changes, it is re-rendered.

import { useRef, useState } from "react";

const App = () => { const count = useRef(0); const [myBool, setMyBool] = useState(false);

const increment = () => {
    count.current++;
    // The value increments
    console.log(`The count is: ${count.current}`);
    setMyBool(!myBool);
}

// The value displayed on the button now changes
return <button onClick={increment}>The count is {count.current}</button>

}

export default App;

Now, whenever the button is clicked, we set myBool to a new value. This causes the component to re-render. We can see this re-rendering as now the count value is increasing in the UI as well as the console.

useRef Hook and DOM Element Access

The useRef hook can also be used to access DOM elements. To do this, we create a variable with useRef and then we provide it to the ref attribute of a JSX element. For a demonstration, lets create a reference for our button element and change its color to red when it is clicked.

import { useRef, useState } from "react";

const App = () => { const count = useRef(0); // Reference the HTML Button element const buttonRef = useRef(null); const [myBool, setMyBool] = useState(false);

const increment = () => {
    count.current++;
    console.log(`The count is: ${count.current}`);
    setMyBool(!myBool);
    // Change the color to red
    buttonRef.current.style.backgroundColor = 'red';
}

// Button element contains the reference to the button element with the ref attribute
return <button ref={buttonRef} onClick={increment}>The count is {count.current}</button>

}

export default App;

As we are using typescript with react we need to provide a type, HTMLButtonElement, to useRef. TypeScript also requires us to pass an initial value of null as during the initial rendering, React hasn't created the component yet. Therefore, the initial value for a referenced JSX element will be null. As such, it is recommended to work with the reference from useRef either inside an event handler (like we are doing here) or inside the useEffect hook. Nevertheless, we capture our button reference inside a variable called buttonRef. When the button is clicked, we access the current property of the reference, i.e. our button. We can then change its background color by using its style property.

When to use the useRef Hook

The useRef hook should be used when a variable needs updating, but updating the variable does not require a re-render of the component. In other words, using useRef is a good idea when we want to track a value but don't want to trigger a re-render. Remember, useState causes a re-render while useRef does not. Therefore, using useRef as opposed to useState when a re-render is not required will increase efficiency of the application. Furthermore, updating a reference is synchronous while updating state is asynchronous.