Learnitweb

useRef Hook

useRef is a React Hook that lets you reference a value that’s not needed for rendering.

const ref = useRef(initialValue)

Call useRef at the top level of your component to declare a ref.

import { useRef } from 'react';

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

Parameters

initialValue: The value you want the ref object’s current property to be initially. It can be a value of any type. This argument is ignored after the initial render.

Returns

useRef returns an object with a single property:

  • current: Initially, it’s set to the initialValue you have passed. You can later set it to something else. If you pass the ref object to React as a ref attribute to a JSX node, React will set its current property.

On the next renders, useRef will return the same object.

Changing a ref does not trigger a re-render. This means refs are perfect for storing information that doesn’t affect the visual output of your component. For example, if you need to store an interval ID and retrieve it later, you can put it in a ref. To update the value inside the ref, you need to manually change its current property.

By using a ref, you ensure that:

  • You can store information between re-renders (unlike regular variables, which reset on every render).
  • The information is local to each copy of your component (unlike the variables outside, which are shared).

Changing a ref does not trigger a re-render, so refs are not appropriate for storing information you want to display on the screen. Use state for that instead.

Caveats 

  • You can mutate the ref.current property. Unlike state, it is mutable. However, if it holds an object that is used for rendering (for example, a piece of your state), then you shouldn’t mutate that object.
  • When you change the ref.current property, React does not re-render your component. React is not aware of when you change it because a ref is a plain JavaScript object.
  • Do not write or read ref.current during rendering, except for initialization. This makes your component’s behavior unpredictable.
  • In Strict Mode, React will call your component function twice in order to help you find accidental impurities. This is development-only behavior and does not affect production. Each ref object will be created twice, but one of the versions will be discarded. If your component function is pure (as it should be), this should not affect the behavior.

Examples of referencing a value with useRef

This component uses a ref to keep track of how many times the button was clicked. Note that it’s okay to use a ref instead of state here because the click count is only read and written in an event handler.

import { useRef } from 'react';

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

  function handleClick() {
    ref.current = ref.current + 1;
    alert('You clicked ' + ref.current + ' times!');
  }

  return (
    <button onClick={handleClick}>
      Click me!
    </button>
  );
}

If you show {ref.current} in the JSX, the number won’t update on click. This is because setting ref.current does not trigger a re-render. Information that’s used for rendering should be state instead.

Pitfall

Do not write or read ref.current during rendering.

React expects that the body of your component behaves like a pure function:

  • If the inputs (props, state, and context) are the same, it should return exactly the same JSX.
  • Calling it in a different order or with different arguments should not affect the results of other calls.

Reading or writing a ref during rendering breaks these expectations.

Manipulating the DOM with a ref 

It’s particularly common to use a ref to manipulate the DOM. React has built-in support for this.

First, declare a ref object with an initial value of null:

import { useRef } from 'react';

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

Then pass your ref object as the ref attribute to the JSX of the DOM node you want to manipulate:

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

After React creates the DOM node and puts it on the screen, React will set the current property of your ref object to that DOM node. Now you can access the <input>’s DOM node and call methods like focus():

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

React will set the current property back to null when the node is removed from the screen.

How to avoid null checks when initializing useRef later

If you use a type checker and don’t want to always check for null, you can try a pattern like this instead:

function Video() {
  const playerRef = useRef(null);

  function getPlayer() {
    if (playerRef.current !== null) {
      return playerRef.current;
    }
    const player = new VideoPlayer();
    playerRef.current = player;
    return player;
  }

  // ...

Here, the playerRef itself is nullable. However, you should be able to convince your type checker that there is no case in which getPlayer() returns null. Then use getPlayer() in your event handlers.