Refs is one of those topics that sends even seasoned React devs into fits of panic. What is this mysterious thing called a “ref” that we never encounter and yet is encountered everywhere (in blog posts and interviews, at least!)? Am I less of a React dev if I don’t know how to use refs? Where the heck would I need this ref thing?

Calm down, my friend. The topic of refs might be on the fringes and it might be a bit weird, but it’s by no means mysterious or useless.

HOWEVER . . .

What makes this topic worse are the half-hearted, rushed, and sometimes downright wrong introductions provided by blogs that show up first on Google searches. And so, the average dev — already stricken with Imposter Syndrome — thinks that this is one more difficult area they must master; or, when they can’t fully understand refs from the articles from top search results, the feel that perhaps they aren’t cut out for this job.

But today, we shall put an end to all the mystery and nonsense surrounding refs!

Errr . . . I mean, starting today. Because trying to pack everything into a single article will make you quit as a developer and me as a blog writer. So, in this post, let’s just nibble at the idea and see what comes out.

Refs appear to be a challenge because they sit outside the realm of React, so to speak. As a result, we don’t hear about them that much, and unless our application has some tricky needs, they’re not even considered.

Why?

Call it the fault of the mental model that people develop when they’ve been into the React world for some time. This mental model includes some hidden assumptions, notions, etc., about web applications. Let’s examine some of these:

  • There is something called a Virtual DOM, which mimics the actual DOM.
  • This Virtual DOM is where we develop our applications — state, props, etc.
  • While developing in React, we never think about the real DOM because (see the next point) . . .
  • It’s React’s job to reconcile these two DOMs and apply the necessary updates. This process is, and should be, opaque to the React developer.
  • Because of the virtual DOM, React needs full control of the real DOM, which is why there’s only HTML element in our starting index.html file, which is what becomes the full-fledged app we later see and deploy.

Virtual DOM . . . Real DOM, the bridge between them being React.

And what do we commonly do as React developers? Write components, respond to state changes, fire off functions on common events like onClick(), and so on.

But now and then we come across a use case that React was not designed for. For example, let’s say we have an e-commerce site with typical forms to fill. Our UX dictates that whenever there’s an error in form validation, the focus (cursor) should jump to that (or the first in case of several errors) input. This way, the user can directly start typing and fix the error they see right above/below the input.

How do we do this in React?

We can’t, plain and simple. React, as we know it — Virtual DOM, Real DOM, events, components, props, rendering, etc. — wasn’t designed for this sort of use cases. Or let’s say these use cases are a mess and React decided not to touch them (which is why people still look fondly upon jQuery!).

In any case, this isn’t achievable in standard React. But React does give you a way to directly access the DOM element you’re interested in. You guessed it: this is called Refs (short for “references”, I suppose). So, what are refs, again? They are direct references (pointers is another term we can loosely use here) to DOM elements, allowing us to manipulate them as we wish.

Let’s see some working code. Here’s a simple React component that has a button and a text input. All we want to accomplish is: when the button is clicked, the focus should move to the text box (live playground here).

import React, { useRef } from "react";
import "./styles.css";

export default function App() {
  const ref = useRef();
  return (
    <div className="App">
      <button onClick={() => ref.current.focus()}>Set focus to text box!</button>
      <input type="text" ref={ref}/>
    </div>
  );
}

As you can see, once we have the current ref, we can simply access that DOM element using ref.current. And then, calling focus() does the rest of the trick.

Now, refs might appear brain-dead simple, but you’ll find plenty of warnings about them. Use Refs only, only, only if you know exactly what you’re doing, and so on. But why is that so?

It’s so because if you start taking Refs as a convenience, you’ll make a mess of everything. For example: you can use a ref and change the value inside the text box. But should you? No, because if you do that, you’re performing a change React is not aware of, and all your state management will go for a toss.

So, what can we use Refs? Exactly in the type of scenarios as shown in this post — situations where you have to “reach out” and grab something from the (real) DOM, that is otherwise not available in the React world. Some good examples are: pushing buttons of a media player, interacting with other non-React libraries, setting focus, selecting text, performing a scroll, etc.

I hope Refs won’t be a bugbear to you anymore. Remember, they are deceptively simple, and we must be sure why we’re including them.