What exactly is the `useRef` hook in React?

What exactly is the `useRef` hook in React?

A hook is a function that enables you to use state and other React features inside functional components.

useRef is a type of React hook which accepts a single argument and returns an object. Unlike useState, useRef does not trigger rerender.

import { useRef } from 'react';

export default function App() {
  const elementRef = useRef(0);

  console.log(elementRef)  // {current: 0}

  return <div>App Component</div>;
}

The elementRef here is an object with a property called current which currently represents the initial value passed to the useRef hook. This is a mutable value, we can modify or update it when required.

So what should we use this hook for? What purpose does it serve exactly?

Let's see some of the uses of the useRef hook.

Accessing DOM elements

React follows the declarative approach keeping the functions pure. But what if we want to select a DOM element and interact with it, how do we do it? We useRef!

In React, elements have a special attribute called ref which is used to reference and make it selectable. Let's create a ref for the h1 element and log it to the console to see what we get.


import { useRef, useEffect } from 'react';

export default function App() {
  const headingRef = useRef(0);

  useEffect(() => {
    console.log(headingRef);
  }, []);

  return (
    <div className="App">
        <h1 ref={headingRef}>This is heading</h1>
        <h1>This is paragraph</h1>
    </div>
    );
}

Notice that I am logging the headingRef inside the useEffect hook and not the function body. If you try to access the headingRef inside the function body, then you get the initial value we set into the useRef hook. Since the useEffect hook runs after the component has mounted, it will now point to the h1 element as expected. You can read more about how the useEffect hook works here.

  useEffect(() => {
    console.log(headingRef)  // {current: h1}
    console.log(headingRef.current)  // <h1>This is a heading</h1>
  }, []);

Focus on input when the component mounts

We can also useRef to focus on an input field when the component mounts. For this you need to access the HTMLElement.focus method.

import { useRef, useEffect } from 'react';

export default function App() {
  const inputRef = useRef(0);

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

  return (
    <div>
        <label>
            Username: <input ref={inputRef} type="text"></input>
        </label>
    </div>
  );
}

You can check the demo here.

Preventing rerenders

When you want to remember some value without triggering a rerender, you can useRef.

import React, { useRef } from 'react';

export default function App() {
  const counterRef = useRef(0);

  return (
    <div>
        <h1>Counter : {counterRef.current}</h1>
        <button onClick={() => alert(counterRef.current++)}>
            Increment
        </button>
    </div>
  );
}

Check the demo here.

Here I am using alert only to show the changed value of the counter. Since no rerenders were triggered, the counter value on the screen does not get updated.

Implement a timer using useRef

Suppose we want to implement a timer. We can easily do that with the setInterval function. We can also use the clearInterval() to stop the timer. But what should id should I pass into this function?

React uses functional programming and in functional programming, global variables are avoided. This is where useRef comes in. We can store the timer inside the ref and clear it when required.

import { useRef, useState } from 'react';

export default function App() {
  const [timer, setTimer] = useState(0);
  const timerRef = useRef();

  const startHandler = () => {
    if (!timerRef.current) {
      timerRef.current = setInterval(() => {
          setTimer((prev) => prev + 1);
      }, 1000);
    }
  };

  const stopHandler = () => {
    clearInterval(timerRef.current);
    timerRef.current = null;
  };

  return (
     <div>
        <h1>{timer}</h1>
        <button onClick={startHandler}>Start</button>
        <button onClick={stopHandler}>Stop</button>
    </div>
  );
}

Check the demo here

Conclusion

  • useRef is a hook in React which takes a single input and returns an object.
  • This returned object has a key of current which holds the ref value.
  • useRef's current value is mutable and can be modified.
  • useRef does not trigger rerender.
  • useRef can be used to access DOM elements.