DEV Community

Ayako yk
Ayako yk

Posted on

React Hook: useRef

While working with React Hooks, I came across useRef and encountered some uncertainty. To address this, I decided to refresh my knowledge and learn more about it.

In this blog article, I will discuss two main concepts and their use cases by providing sample code. These examples are based on the React Documentation, serving as a foundation for illustrating the concepts.
React Documentation

Syntax
import { useRef } from 'react';
const ref = useRef(initialValue);

  • An initial value can be of any type.
  • It returns an object with a single property: { current: initialValue }.
  • The ref.current property is mutable, but it's important not to write or read ref.current during rendering.

1. Referencing a value with a ref

When a variable or state changes in React, it triggers a re-render. However, there are situations where we want to retain the value of a variable without triggering re-renders. This is where useRef comes in handy as it allows us to store and access such values. Some people often refer to this capability as having a 'box' to store the value.

First, let's see how useRef works.

import React, { useRef } from "react";

export default function Counter() {
  let ref = useRef(0);

  const handleClick = () => {
    console.log("ref.current", ref.current);
    ref.current = ref.current + 1;
  };

  return (
    <>
      <button onClick={handleClick}>Click!</button>
      <h3>{ref.current}</h3>
    </>
  )
}
Enter fullscreen mode Exit fullscreen mode

Image description

When clicking the button, nothing happens; the value of 0 remains unchanged. However, if you inspect the console, you will notice that the counter is incrementing. In contrast, if you had used useState, the value of 0 on the browser would change as you click.

Image description

Use cases:
When using setInterval or setTimeout we get a numerical ID (intervalID or timeoutID). We need to keep this ID when canceling the interval or timeout (clearInterval or clearTimeout).
When refreshing the page, we get a new ID again.

The code below is from the React Document.

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

export default function Stopwatch() {
  const [startTime, setStartTime] = useState(null)
  const [now, setNow] = useState(null)
  const intervalRef = useRef(null)

  function handleStart() {
    setStartTime(Date.now())
    setNow(Date.now())

    clearInterval(intervalRef.current)
    intervalRef.current = setInterval(() => {
      setNow(Date.now())
    }, 10)
  }

  function handleStop() {
    clearInterval(intervalRef.current)
    console.log("intervalRef clear", intervalRef.current)
  }

  let secondsPassed = 0
  if (startTime != null && now != null) {
    secondsPassed = (now - startTime) / 1000
  }

  return (
    <>
      <h1>Time passed: {secondsPassed.toFixed(3)}</h1>
      <button onClick={handleStart}>Start</button>
      <button onClick={handleStop}>Stop</button>
    </>
  )
}
Enter fullscreen mode Exit fullscreen mode

2. Manipulating the DOM with a ref

Yes, DOM!

With the use of useRef, we can accomplish the same thing using useRef instead of document.getElementById('myInput').focus().

const myRef = userRef(null);   // { current: null }
<input ref={myRef} />
Enter fullscreen mode Exit fullscreen mode

What these two lines of code do is create a reference to the corresponding DOM node and store it in myRef.current. By doing so, you gain the ability to access this specific DOM node within your event handlers and utilize the browser APIs that are available on it.

Now, this makes sense to me.
myRef.current.style.color = 'red';

Some methods of ref.current
Component methods: play(), pause(), open(), close()
DOM element: focus(), blur(), scrollIntoView()
DOM element: contains()

The contains() method allows you to check whether a specific DOM element is a descendant of the element associated with the ref. This functionality can be particularly useful for implementing open/close modal behavior.

function myComponent(){
    const divRef = useRef(null);

    function handleClick(){
        if(divRef.current.contains(event.target)){
            console.log("Clicked inside the div element or inside the modal.");
        } else {
            console.log("Clicked outside the div element. You can implement the close-the-modal function here.");
        }
    };

    return (
        <div ref={divRef} onClick={handleClick}>
            Click inside or outside this dev element.
        </div>
    )
}
Enter fullscreen mode Exit fullscreen mode

In summary, useRef offers the ability to store a value without triggering re-renders and facilitates the manipulation of DOM elements, enabling the creation of dynamic functionalities.

Top comments (0)