React useRef: A complete guide with examples
React userRef: A Complete guide with examples

React useRef: A complete guide with examples

Dead Simple Chat Team

useRef is a react hook. That lets you reference a value that is not needed for rendering

The react useRef returns a mutable object with a 'current' property. This Object remains persistent throughout the lifecycle of a component.

You can store data in this object and the data persists across re renders.

In another words, useRef returns a single current Object with an initial value that you provide, on the next renders the useRefs return the same current property with the data that you provided.

Dead Simple Chat allows you to easily add Chat to any React Application using powerful Javascript Chat SDK.

You can change its current property to store data and read it later. This might remind you of state but there is a differnce here. State causes the component to re render but useRef does not trigger a re-render

example of a useRef

function handleStartClick() {
  const intervalId = setInterval(() => {
    // ...
  }, 1000);
  intervalRef.current = intervalId;
}
example of a useRef

refs are perfect for storing values that do not affect the visual output of a component. Because change in current property of a ref does not cause the component to re render

Let us take an example of an intervalId that you might want to store and retrieve it later.

To update the ref you need to manually change its property.

function handleStopClick() {
  const intervalId = intervalRef.current;
  clearInterval(intervalId);
}

By using a ref you get

  • The information stored is local to each copy of the component
  • changing the information does not trigger a re render (unlike state variable which do trigger a re render)
  • store information between re render (unlike regular variables, which reset on re render)

To choose between useRef and useState keep in mind that the use ref does not trigger a re render and the useState does trigger it. So, it might  not be a good idea to store UI related information in useRef

import { useRef } from "react";

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

  function handleClick() {
    ref.current = ref.current + 1;
    alert("You clicked the button " + ref.current + "Times");
  }

  return <button onClick={handleClick}>Click the button!</button>;
}

This component Counter uses a ref to keep track of how many times the user has pressed the button

useRef example

Let us consider another example:

Here we have created a Stop Watch with start and stop button. User can start the timer and stop the Stop Watch.

In this example we will use both useState and useRef as a means to differentiate their uses

import { 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);
  }

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

  return (
    <>
      <h1>Time passed: {secondsPassed.toFixed(3)}</h1>
      <button onClick={handleStart}>Start Timer</button>
      <button onClick={handleStop}>Stop Timer</button>
    </>
  );
}
Timer Example

Here we have the StartTime and now variables that are state variables because they are used for rendering.

intervalRef is a ref used to store ID returned by setInterval

handleStart

handleStart function when called sets the StartTime and now

variable to current time and clears any existing intervalRef value

Creates a new Interval with setInterval function and sets the intervalRef value to current time.

HandleStop

handlestop Clears the interRef with the clearInterval function and calculate the time that has passed.

lastly we render the Stopwatch component.

Dead Simple Chat allows you to easily add Chat to any React Application using powerful Javascript Chat SDK.

Use-cases for useRefs

Dead Simple Chat allows you to easily add Chat to any React Application using powerful Javascript Chat SDK.

  1. Accessing DOM elements: Userefs allow us to store DOM and manipulate DOM elements. That allows us to access the elements properties without using state or porps
  2. Storing Prev values of state or props: Sometimes you need to access the previous value of state or a prop. You can store that value in a ref and access it later on
  3. Storing values of Instance variable: Instance variables are specific to a components instance and do not store the data that affects the components render. Thus their values can be easily stored in a ref
Dead Simple Chat allows you to easily add Chat to any React Application using powerful Javascript Chat SDK.

How to manipulate DOM elements with a ref

Manipulating the DOM with React useRef is pretty easy. Use the useRef hook to create a reference to the DOM element that you want to manipulate, then access its properties and methods without having the component to re render

lets learn more in detail

  1. Declare a ref object with a initial value of null
import { useRef } from 'react';

function MyComponent() {
  const inputRef = useRef(null);
  // ...
}

The DOM node that you want to manipulate. Pass the ref object as a attribute to the JSX like so

  // ...
  return <input ref={inputRef} />;

Once the DOM node is rendered on the screen by React. The DOM node will be set to the current property of the ref Object. Now you can access the DOM node and its properties and methods

In the above example you can access the input property's DOM node and call its methods like focus()

function handleCLick(){
    inputRef.current.focus();
}

Note: The react will set the current property of the inputRef to null once the DOM node is removed from the screen.

Dead Simple Chat allows you to easily add Chat to any React Application using powerful Javascript Chat SDK.

Examples of manipulating DOM with useRef

  1. Clicking the button focuses the input
import { useRef } from 'react';

export default function Form() {
  const inputRef = useRef(null);

  function handleClick() {
    inputRef.current.focus();
  }

  return (
    <>
      <input ref={inputRef} />
      <button onClick={handleClick}>
        Focus the input
      </button>
    </>
  );
}
Clicking the button focuses the input
Clicking the button focuses the input
  1. we are importing useRef from react then
  2. we are creating a function named form
  3. we are declaring a const inputRef and setting it to useRef(null)
  4. then we are creating a handleClick function and then calling the focus on the inputRef current property
  5. on the return statement we are assigning the inputRef to the button element
  6. thus the button elements props and methods can be callled on the inputRef and we are calling the focus method above on the inputRef iteself

2. Scrolling an image into view

import { useRef } from 'react';

export default function CatFriends() {
  const listRef = useRef(null);

  function scrollToIndex(index) {
    const listNode = listRef.current;
    // This line assumes a particular DOM structure:
    const imgNode = listNode.querySelectorAll('li > img')[index];
    imgNode.scrollIntoView({
      behavior: 'smooth',
      block: 'nearest',
      inline: 'center'
    });
  }

  return (
    <>
      <nav>
        <button onClick={() => scrollToIndex(0)}>
          Tom
        </button>
        <button onClick={() => scrollToIndex(1)}>
          Maru
        </button>
        <button onClick={() => scrollToIndex(2)}>
          Jellylorum
        </button>
      </nav>
      <div>
        <ul ref={listRef}>
          <li>
            <img
              src="https://placekitten.com/g/200/200"
              alt="Tom"
            />
          </li>
          <li>
            <img
              src="https://placekitten.com/g/300/200"
              alt="Maru"
            />
          </li>
          <li>
            <img
              src="https://placekitten.com/g/250/200"
              alt="Jellylorum"
            />
          </li>
        </ul>
      </div>
    </>
  );
}
App.Js

We are using the useRef hook (listRef) to reference a list of cat images in the CatFriends component.  

This reference allows the user to scroll quickly a specific cat by pressing a button.

we create a scrollToIndex function

The scrollToIndex takes index as an argument and scrolls to the corresponding index from the list

First it retrieves the DOM element using the listRef.current property, then finds the image from the DOM element using queryselector('li>img')

This line assumes a particular DOM structure specifically there is an img inside of an li tag

Then scrolls the page to the selected img DOM element using scrollIntoView()

Then render theCatFriends component with three buttons each representing a cat.

Dead Simple Chat allows you to easily add Chat to any React Application using powerful Javascript Chat SDK.

Avoid Recreating the ref contents

React saves the initial value of a ref and ignores it in re renders.

function Video() {
  const playerRef = useRef(new VideoPlayer());
  // ...

In the above example new VideoPlayer() is only used for the initial render, and you are calling this function on every render. This is wasteful if you are creating expensive objects

To solve the you can initialize the ref like this

function Video() {
const playerRef = useRef(null);
if (player.current === null){
playerRef.current = new VideoPlayer();
}

first set the ref to null then only create the VideoPlayer if the ref is null. This ensures that the VideoPlayer is only created once.

If VideoPlayer is an expensive resource, creating VideoPlayer once and using it again will save resources

Normally it is not recommended to change a ref during rendering but in this case its ok because we the result is going to be the same.

Dead Simple Chat allows you to easily add Chat to any React Application using powerful Javascript Chat SDK.

Pitfalls of using inputRefs

  1. Do NOT read or write ref.current during rendering
  2. You can read or write from event handlers or effects instead
  3. If you have to read or write something during rendering useState instead

Dead Simple Chat allows you to easily add Chat to any React Application using powerful Javascript Chat SDK.

Conclusion

In this article we learnt about the react useRef. We used examples to better understand what `useRef` is and what is the difference between useRef and useState

useRef does not re render the component whereas useState does re render the component.

Both can store properties and data inside of them. The data does not clear with DOM or component re render and you  have to manually clear the data

thank you for reading.

Dead Simple Chat allows you to easily add Chat to any React Application using powerful Javascript Chat SDK.