DEV Community

loading...
Cover image for All about React's createRef method

All about React's createRef method

asayerio_techblog profile image Asayer Tech Blog Originally published at blog.asayer.io ・6 min read

by Felix Gerschau

React refs are a useful and powerful tool that we can use to get even more control over the elements in our application.

In this article, you'll learn what you need to know about refs and how to use them in your class and function components.

Do you want to see a working example? Click here to skip the explanation.

Or have a look at the codepen here.

What are refs in React?

"Ref" is short for reference, and it's a React feature that allows us to store a component or DOM element of our application in a variable and access it programmatically.

We can use refs to access DOM elements and React components.

When (not) to use refs

The official React documentation states that the following use cases are a good fit for using refs:

  • Managing focus, text selection, or media playback.
  • Triggering imperative animations.
  • Integrating with third-party DOM libraries.

They also say that we should avoid using refs for anything that can be done declaratively.

Declaratively in React means we should use the JSX syntax whenever we can, instead of using JavaScript to update our application.

Leaving the DOM updates to React makes sense. After all, React is designed to update the elements on our websites as efficiently as possible.

Sometimes though, React doesn't provide the functionality we need, in which case we need to fall back to plain JavaScript.

If we were to get a DOM element in Vanilla JavaScript, we'd use functions like document.getElementById or document.getElementsByClassName.

const inputElement = document.getElementById('input-element-id');
inputElement.focus();
Enter fullscreen mode Exit fullscreen mode

But React offers a more convenient way to access elements in our application: Refs.

Every class component and HTML element in React accepts the ref prop, which we can use to store a reference to this element.

How to use createRef

That was enough of theory for now. Let's have a look at how we can use refs in our applications.

For this tutorial, I created a small codepen that allows you to enter your name and focus the input when you click on the button.

React createRef example

The HTML input element doesn't accept any focus prop that we could use to focus it. However, the HTML node does expose the focus function.

We somehow need to get access to the element in our code so we can call this function. Instead using getElementById, we'll use React's refs.

First, we need to create a new variable in our class where we will store the reference. Mine has the creative name inputRef.

constructor(props) {
  super(props);
  this.inputRef = React.createRef();
  // ...
}
Enter fullscreen mode Exit fullscreen mode

We initialize the variable with createRef, which allows us to simply pass the variable to the element that we want to reference.

<input
  ref={this.inputRef}
  value={this.state.name}
  onChange={this.handleInputChange}
/>
Enter fullscreen mode Exit fullscreen mode

That's everything we need to do to get access to the input element.

The inputRef variable now contains a reference to the input element.

If we were to inspect the variable at this point, it would look something like this.

▶ Object
  ▶ current: input
  ▶ __proto__: Object
Enter fullscreen mode Exit fullscreen mode

We can focus the input element by calling the focus function in the onClick handler function.

<button
  onClick={() => this.inputRef.current?.focus()}
>
  Focus
</button>
Enter fullscreen mode Exit fullscreen mode

In case you are wondering, adding the question mark is called the optional chaining, first introduced by TypeScript. It allows us to safely access current without worrying about it being undefined or null.

Full example

Putting everything together, the code of that component looks like the following:

class App extends React.Component {
  constructor(props) {
    super(props);
    this.inputRef = React.createRef();
    this.state = {
      name: '',
    };
  }

  handleInputChange = (e) => {
    e.preventDefault();
    this.setState({ name: e.target.value });
  }

  render() {
    return (
      <>
        <h1>Hi {this.state.name || 'there'}! ??</h1>
        <p>
          What's your name?
        </p>
        <input
          ref={this.inputRef}
          value={this.state.name}
          onChange={this.handleInputChange}
        />
        <button
          onClick={() => this.inputRef?.current?.focus()}
        >
          Focus
        </button>
      </>
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

This code is also available on codepen.

Referencing class components

With refs, we can also reference other React components. When we do this, instead of receiving a DOM node, current will contain the mounted instance of that component.

Note that this doesn't work with function components because, unlike class components, they don't have instances.

When dealing with class components, the syntax is the same as with DOM elements:

<MyComponent ref={this.myComponentRef} />
Enter fullscreen mode Exit fullscreen mode

You don't need to change anything in MyComponent.

Referencing function components using forwardRef

I know that just one moment ago I said that you can't reference function components. However, if you really need to do this, you can forward the ref to a DOM element.

For that, we use the forwardRef function.

const MyInputComponent = React.forwardRef((props, ref) => (
  <input ref={ref} />
));
Enter fullscreen mode Exit fullscreen mode

This doesn't allow us to reference the functional component itself but one of the native elements that it renders.

With this modification, we can use the ref prop as we did with class components and HTML elements.

const MyInputComponent = React.forwardRef((props, ref) => {
  return (
    <input
      ref={ref}
      value={props.name}
      onChange={props.onChange}
    />
  );
});
Enter fullscreen mode Exit fullscreen mode

In App we can pass down the ref property like before.

class App extends React.Component {
  //...

  render() {
    return (
      <>
        <MyInputComponent
          ref={this.inputRef}
          name={this.state.name}
          onChange={this.handleChange}
        />

      </>
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

I created a seperate codepen for this example.

Other ways to reference elements

Above I only explained one way of creating refs because I believe it's the easiest way of doing so.

You can do this differently though, and you might encounter these ways of creating refs in some code bases.

Callback refs

The ref prop, besides accepting objects created with createRef, also accepts a callback.

<input
  ref={(e) => this.inputRef = e}
  value={this.state.name}
  onChange={this.handleInputChange}
/>
Enter fullscreen mode Exit fullscreen mode

Note that we don't access the current field in the callback because the function directly receives the element.

Because of this, we don't need to initialze the variable with createRef. We can set it to null in the constructor:

constructor(props) {
  super(props);
  this.inputRef = null;
  this.state = {
    name: '',
  };
}
Enter fullscreen mode Exit fullscreen mode

When accessing the element in our code, we can again omit current as inputRef already contains the element:

<button
  onClick={() => this.inputRef?.focus()}
>
  Focus
</button>
Enter fullscreen mode Exit fullscreen mode

The callback will be called with the element once the component mounts, and it will be called with null before the component unmounts.

React guarantees that it will be up to date before componentDidMount or componentDidUpdate are executed.

How to use useRef

The createRef function we know from class components also has its counterpart for functional components: The useRef hook.

We first need to initialize the variable.

const inputRef = useRef(null);
Enter fullscreen mode Exit fullscreen mode

We then pass this value to the ref prop:

<input
  ref={inputRef}
  value={name}
  onChange={handleChange}
/>
Enter fullscreen mode Exit fullscreen mode

The usage of this hook is very similar to createRef. However, there are some other use-cases that I discuss in my article about React's useRef hook.

Observability for Production React Apps

While you're testing the createRef method, and how to interact directly with DOM references, debugging your React apps in production may be challenging and time consuming. Asayer is a frontend monitoring tool that replays everything your users do and shows how your app behaves and renders for every issue. It’s like having your browser’s inspector open while looking over your user’s shoulder.
Asayer Frontend Monitoring
Asayer helps to quickly get to the root cause by reproducing issues as if they happened in your own browser. It also monitors your frontend performance by capturing key metrics such as page load time, memory consumption and slow network requests as well as Redux actions/state.
Happy debugging, for modern frontend teams - Start monitoring your web app for free.

Conclusion

React's refs are a useful tool for situations where we can't do things the "React way".

I hope that with this article, you have a good overview of how and when to use them.

Discussion (0)

pic
Editor guide