How many times has it happened when you are working on a React application you want the parent component to interact with their children? It’s quite common thing to handle the parent-child relationship inside a single component.

Usually, the most common approach is to use props. You can then use them with new props to re-render components. But what if you want to access DOM nodes or elements? Here’s where React Refs come into play. Let’s learn more about it.

What are React Refs?

  • ReactRefs provide a way to access DOM nodes or React elements created in the render method.

This is highly useful when you need to modify a child component outside of the typical React dataflow with props. Refs provide you with a cool alternative when the child is a DOM element or an instance of another React component.

Where Refs are used?

Refs are a great addition to the React ecosystem but you should not use them where anything can be done declaratively. Other than that there are some of the following use cases of Refs:

  1. Managing the focus state, text selection, or media playback.
  2. While adding animations crucial to your application context.
  3. Using it with some third-party DOM libraries.

How to use Refs?

It’s time to write some code! But first, let’s see how we can create Refs in general. You can create a new Ref using the React.createRef() API and then attach it to the elements via the ref attribute. Here’s a simple example where myRef is used in a class component:

class MyComponent extends React.Component {

  constructor(props) {

    super(props);

   this.myRef = React.createRef();

 }

  render() {

   return <div ref={this.myRef} />;

 }

}

Now let’s take a look at one realistic example. Let’s say we need to grab a node element. For that we can write a React class component as:

class MyButton extends React.Component {

  render() {

    const { btnLabel, btnAction } = this.props

    return (

      //..

      <button onClick={btnAction}>{btnLabel}</button>

    )

  }

}

As you can see, we used props here but the <button> in JSX here is called as React.createElement(‘button’) which is not exactly an HTML button element. Instead, we get a React element with this! 

Now what to do to gain access to the actual HTML button element here? Yes, you use Refs to create a reference and then pass to the element in JSX you want to. So the above class component now changes to:

class MyButton extends React.Component {

  constructor() {

    super()

    this.btnRef = createRef()

  }

  render() {

    const { btnLabel, btnAction } = this.props

    return (

      <button onClick={btnAction} ref={this.btnRef}>{btnLabel}</button>

    )

  }

}

Of course, we need a constructor to access the current context using this where we also define the btnRef ref. So now we have a way to access the actual HTML button element as this.btnRef.current.

Using Refs for focus control

This is one of the most common use cases of using React Refs. To achieve focus of any element we can call the focus() method. If you have a custom input component then the ref attribute can be used to store a reference to the DOM node and the focus() method to explicitly focus the custom input element.

Here’s an example of the same:

class CustomInput extends React.Component {

  constructor(props) {

    super(props);

    this.customInput = React.createRef();

    this.focusCustomInput = this.focusCustomInput.bind(this);

  }

  focusCustomInput() {

    this.customInput.current.focus();

  }

  render() {

    return (

      <div>

        <input type="text" ref={this.customInput} />

        <input type="button" onClick={this.focusCustomInput} />

      </div>

    );

  }

}

In the above code, we first create a new ref to store the textInput DOM element. Make sure you notice that we are actually binding the custom input value with the current value passed by the user. Further, this goes to the focusCustomInput() method where we explicitly define to focus the input to access the current value to get the DOM node. 

Now if you want to use the same concept with the React lifecycle methods like componentDidMount or componentDidUpdate then, we could use a ref to access the custom input calling the focusCustomInput() method manually:

class FocusInput extends React.Component {

  constructor(props) {

    super(props);

    this.customInput = React.createRef();

  }

  componentDidMount() {

    this.customInput.current.focusCustomInput();

  }

  render() {

    return (

      <MyCustomInput ref={this.customInput} />

    );

  }

}

Also Read: Using Data Grid component in MUI X with React

The case of forwardRef

These days web apps are mostly SPAs (Single Page Applications), they are more complex and we use plain HTML code very little in them. With that said, it becomes very easy to have more than one DOM node to encapsulate more logic around the view behaviour. Here’s a quick example:

const LabelledInput = (props) => {

  const { id, label, value, onChange } = props

  return (

    <div class="labelled--input">

      <label for={id}>{label}</label>

      <input id={id} onChange={onChange} value={value} />

    </div>

  )

}

export default LabelledInput

The issue arises when passing a ref to this component. Doing so, it will return its instance i.e. a React component reference and not the actual input element we want to focus.

React does have a workaround here with forwardRef, this allows you to define internally what element the ref will point to. For this to work, we pass a second argument to the LabelledInput() function and place it to use on the desired input element. When the parent component passes a ref value, it will get the inout which will be used to avoid exposing the properties of a component. Here’s our updated code:

const LabelledInput = (props, ref) => {

  const { id, label, value, onChange } = props

  return (

    <div class="labelled--input">

      <label for={id}>{label}</label>

      <input id={id} onChange={onChange} value={value} ref={ref}/>

    </div>

  )

}

export default React.forwardRef(LabelledInput)

Refs make it possible to access DOM nodes directly within React. One of the most common use cases can be found in using it when changing child of a parent component. In this short tutorial, you got to know how to use it with forms while handling state in a class component. From here, you can read the following topics to better understand React Refs: