React useRef

Image of Author
March 26, 2022 (last updated September 18, 2024)

In React a ref is a bucket. You create the bucket and give it to React internals. React internals put a reference to a DOM node in that bucket. Now, you can programmatically reach into that bucket and access the DOM node underlying a jsx element, and perform imperative actions on it, like adding or removing a class, etc.

Create a ref

Create a ref via useRef

function Component() {
  const divRef = useRef();
}

This creates an "empty bucket" called divRef (call it something semantically valuable).

JSX to DOM Node

Internally, React turns JSX elements into DOM nodes. (Terminologically, MySpan is a functional React component, and <span> is a JSX element, which turns into a React element, which turns into a DOM node.)

function MySpan() {
  return <span>Hello</span>;
}

The above, declarative, React component, tells React internally to create a DOM node. The React internal, imperative sequence of commands would look something like this, eventually

const span = document.createElement("span");
const text = document.createTextNode("Hello");
span.appendChild(text);

Accessing the DOM node

React will eventually have access to the DOM node that corresponds to each JSX element. This means that if you ask for the DOM node, React can give it to you, eventually, once it's been created. React created the ref interface as the way to do this. This is the (historical) purpose of refs. Create an empty bucket, pass it to a JSX element, React will notice (because ref is a reserved word in React, and so can only be used for this purpose), and, once React creates the underlying DOM node, it will put a reference to that dom node in the bucket so that you too now have access to it.

The dom node is stored under ref.current. A ref is mutable, but mutations do not cause rerenders.

function Component() {
  const divRef = useRef();

  console.log(ref.current); // initially null
  setTimeout(() => console.log(ref.current), 500); // eventually a DOM node

  return <div ref={divRef}>Hello, World!</div>;
}

Not the Blessed Child

Don't overuse refs. They are not the ideal way to use React because React is trying to provide a declarative overlay to the inherently imperative DOM. Asking for the underlying DOM node, which implicitly is a request to execute imperative commands, goes against the declarative nature of React, and as such should be avoided. Learn more about this via the React doc: Refs and the DOM.