Understanding the React useRef() Hook

Understanding the React useRef() Hook

Written by Raunaq on Aug 12th, 2021 Views Report Post

Introduction

In this post, we'll look at the useRef() hook that provides a way to directly access a DOM node. We'll also look at scenarios where we can use the value of the reference returned by the Ref hook that is persisted between component re-renderings.

Prerequisites

useRef() Hook

useRef Hook provides a way to directly access a DOM node within a functional component. In order to use the Ref Hook to access the DOM node, use the following steps

  • First, you need to import useRef Hook from the react package
import { useRef } from "react"
  • useRef(initialValue) returns a reference which is a mutable ref object. This returned object will persist for the entire lifetime of the component.
const refObject = useRef(initialValue)

refObject has a current property that is initialized with the argument passed to useRef

  • Now, in order to access the required DOM element, pass a ref attribute to that element and assign refObject to it.
<input ref={refObject} type="text" />
  • Now, you can access the DOM node using refObject.current

Directly accessing a DOM node should only be done in certain scenarios such as managing focus, text selection and triggering imperative animations.

Now, take a look at the following functional component using the useRef Hook

import React, { useEffect, useRef } from "react";

export default function App() {

  const inputRef = useRef(null);

  useEffect(() => {
    inputRef.current.focus()
  },[]) 

    return (
      <div>
        <p>Enter email:</p>
        <input ref={inputRef} type="text" />
      </div>
    );
}

Here, the Ref Hook is used to add focus to the input textbox. After the component is rendered to the screen, the useEffect runs and since the inputRef.current holds the DOM element, inputRef.current.focus() puts the cursor on the input textbox.

Accessing a DOM node using the ref attribute is not the only use that useRef offers. Since, the Ref Hook returns a mutable ref object whose .current property can hold a value till the entire lifetime of the component, you can use this to keep any mutable value around which can be used later.

useRef() creates a plain JavaScript object but the difference between useRef() and creating an object with current property {current: ...} yourself is that the Ref Hook will give you the same ref object on every render. Additionally, mutating the .current property does not cause a re-render and therefore useRef will not notify you when its content changes.

Let's take a look at the following functional component where the Ref Hook is used to keep track of the previous state

import React, { useState, useEffect, useRef } from "react";

export default function App() {

  const [version, setVersion] = useState(1)

  const prevVersionRef = useRef(0)

  useEffect(() => {
    prevVersionRef.current = version
  })
  
    return (
      <div>
        <p>Latest Version: {version} Previous Version: {prevVersionRef.current}</p>
        <button onClick={() => setVersion(1 + version)}>New Version</button>
      </div>
    );
}
  • After the App component gets rendered to the screen with a paragraph Latest Version: 1 Previous Version: 0 and a button, the side effect runs which mutates the .current property of the prevVersionRef object to 1.

  • As mutating the .current property does not cause a re-render and it can hold that value between re-renders; when you click the button to update the version, the component re-renders.

  • This causes the version to update to 2 and prevVersionRef.current keeps the value 1 intact. After the component is re-rendered, the text on the screen updates to Latest Version: 2 Previous Version: 1. The effect runs again mutating the .current property to 2.

This is how previous state value can be stored using the Ref Hook.

Now, let's take a look at another example

import React, { useState, useEffect, useRef } from "react";

export default function App() {

  const [timer, setTimer] = useState(0)

  const timerRef = useRef()

  useEffect(() => {
    const timerId = setInterval(() => {
      setTimer(prevTimerValue => prevTimerValue + 1)
    }, 1000)
    timerRef.current = timerId
  },[])

    return (
      <div>
        <p>Timer: {timer}</p>
        <button onClick={() => clearInterval(timerRef.current)}>Clear Timer</button>
      </div>
    );
}
  • After the App component gets rendered to the screen, React moves to the side effect and sets up a timer using setInterval.

  • Suppose, you want to clear that timer on click of a button and since the timerId variable can only be used inside the Effect Hook, you cannot clear the timer by using that variable in an event handler.

  • Therefore, in order to clear the timer from an event handler, you can store the timerId to the .current property of the timerRef object and use it inside the event handler to clear the timer on clicking the button.

Conclusion

In this post, you got an understanding on how to use the useRef hook. We were able to access a DOM element and provide focus to it using the Ref hook. We also looked at scenarios where we used the value stored in .current property of the mutable ref object.


Thanks for taking the time to read this post. I hope this post helped you!!😊😃 If you liked it, please share.

It would be great to connect with you on Twitter. Please do share your valuable feedback and suggestions👋

Comments (0)