August 6, 2020

CreateRef and UseRef: Difference Between React Refs

If you have been a long time React user, you would have come across createRef and useRef refs to bypass the typical React dataflow and access a DOM element or a React component. At first glance, these two provide the same functionalities. When you look closer at how each of them functions, though, this is not the case. So, if you are someone who is confused by the differences between createRef and useRef, we brought this article for you.

Please subscribe for web development tutorials

What do CreateRef and UseRef Do?

Before digging into their differences, let’s see how and where we can use refs in React.

In React, refs provide an escape hatch to directly access React components or DOM elements instead of through props and component state. This gives us the opportunity to modify the values associated with the React component or DOM element without changing its state.

React documentation recommends the use of refs for the following purposes.

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

Let’s see how we can use createRef and useRef to manage focus on a DOM element.

Change Focus to a DOM Element using Refs

DOM API provides the focus() method to easily change the focus on a DOM element. For this, we have to access the DOM element through React, which we can achieve using refs. 

First, we will use createRef for this task. 

import React, { createRef } from "react";

class TextInput extends React.Component {
    constructor(props) {
      super(props);
      // create a ref to store the DOM element using createRef
      this.textInput = createRef();
    }
  
    focusOnInput() {
      //use textInput.current to access the current the text input DOM
      this.textInput.current.focus();
    }
  
    render() {
     
      return (
        //pass the created textInput as the value of the ref attribute of the input element
        //this creates a DOM instance of the input element and stores it in textInput 
        <div>
            <input ref={textInput} type="text" />
            <button onClick={focusOnInput}>Focus on text input</button>
        </div>
      );
   }
}

Clicking the button instantly changes the focus on the input element by calling the focus() method on the Input element. 

Now, let’s see how to achieve the same task using useRef. But this time, instead of a class component, we are using a function component. There is a reason for this, and we will discuss it in the next section. 

import React, { useRef } from "react";
    
  function TextInput () {
    // create a ref to store the DOM element using useRef
    const textInput = useRef()
 
    const focusOnInput = () => {
        //use textInput.current to access the current the text input DOM
        textInput.current.focus()
    }
 
    return (
        //pass the created textInput as the value of the ref attribute of the input element
        //this creates a DOM instance of the input element and stores it in textInput 
        <div>
            <input ref={textInput} type="text" />
            <button onClick={focusOnInput}>Focus on text input</button>
        </div>
    )
}

We can pass a value when initializing createRef or useRef, and we can use the current property of the referenced DOM instance to access this value.

class ValueComponent extends React.Component {
    constructor(props) {
      super(props);
      this.valueComponent = createRef(10);
    }
    
    changeValue(){
        this.valueComponent.current+=1
    }

    render() {
     
      return (     
        <div>
            <div ref={this.valueComponent}>Value: {this.valueComponent.current}</div>
            <button onClick={this.changeValue}>Change Value</button>
        </div>
      );
    }
}

Now, even if we click the change value button, it doesn’t change the value displayed inside the ValueComponent’s div. Modifying the ref does not modify the state of the component, therefore it is not rerendered and the displayed value stays the same. 

This is how we can use refs to directly access the DOM or React components. But as the above examples show, we can use both createRef and useRef to do the same task. So, are they really different, and if they are, how are they different?

What is the Difference Between CreateRef and UseRef?

The major difference between createRef and useRef is that we should use createRef inside class components and useRef inside function components. 

In the previous examples of using refs to focus on the input element, we used createRef inside a class component and useRef inside a function component as we are supposed to do. But why can’t we use these refs the other way around? 

Can We Use CreateRef inside a Function Component?

Let’s see an example of using createRef inside a function component. 

function TextInput () {
    const textInput = createRef()
 
    const focusOnInput = () => {
        textInput.current.focus()
    }
 
    return (
        <div>
            <input ref={textInput} type="text" />
            <button onClick={focusOnInput}>Focus on text input</button>
        </div>
    )
}

So far in this example, using createRef doesn’t have any difference to using useRef. Both refs successfully achieve what they are supposed to do in this situation. 

What if we use createRef instead of useRef inside the following ValueComponent function?

function ValueComponent () {
    const valueCOmponent = createRef(10)
 
    const changeValue = () => {
        this.valueComponent.current += 1
    }

    return (
        <div>
            <div ref={valueComponent}>Value: {valueComponent.current}</div>
            <button onClick={changeValue}>Change Value</button>
        </div>
    )
}

Still, we can get away with using createRef inside a function component. But what happens if we rerender the element after changing the value stored in ref?

function ValueComponent () {
    const valueComponent = React.createRef(10)
    const {state, setState} = React.useState()

    return (
        <div>
            <div ref={valueComponent}>Value: {valueComponent.current}</div>
            <button onClick={() => (valueComponent.current = 2, setState({}))}>Change Value</button>
        </div>
    )
}

When we click on the button, we expect to see the value inside the div to change to 2 from the initial value of 10. In reality, though, the value displayed is not 2 but 10. What is the reason for this? 

When a function component rerenders, it behaves like a normal function and implements the full content in function logic. In this case, even though the value of valueComponent.current changes to 2 when we click the button, it changes again to 10 when the component rerenders. So, as we see, the displayed value does not change as expected. 

createRef works with class components in this scenario because rerendering a class component only calls the render() function of the component. Bue given the nature of function components, we cannot use createRef with them in the same manner. Instead, we have to use useRef. 

useRef does not reinitialize its values every time a function component rerenders. Instead, it persists the value stored throughout the lifetime of the component. 

function ValueComponent () {
    const valueComponent = React.useRef(10)
    const {state, setState} = React.useState()

    return (
        <div>
            <div ref={valueComponent}>Value: {valueComponent.current}</div>
            <button onClick={() => (valueComponent.current = 2, setState({}))}>Change Value</button>
        </div>
    )
}

Now, when we click the button, the value changes to 2.

Summary

When using React for frontend development, there are times we have to step outside the typical dataflow to directly access the DOM elements and React components. We use createRef and useRef APIs for this purpose. Though the two refs behave the same way most of the time, there is a major difference between the two: createRef should be used inside class components and useRef should be used inside function components. With that in mind, you can use React refs in your program without debating on which one to choose from today onwards. 

Please subscribe for web development tutorials

Leave a Reply

Your email address will not be published. Required fields are marked *