Codementor Events

useRef Hook as mutable ref object.

Published Sep 06, 2019
useRef Hook as mutable ref object.

React official documentation define useRef as:

The useRef Hook is a function that returns a mutable ref object whose .current property is initialized to the passed argument (initialValue). The returned object will persist for the full lifetime of the component.

const refContainer = useRef(initialValue);

A common use case is to access a child imperatively:

function TextInputWithFocusButton() {
  const inputEl = useRef(null);
  const onButtonClick = () => {
    // `current` points to the mounted text input element
    inputEl.current.focus();
  };
  return (
    <>
      <input ref={inputEl} type="text" />
      <button onClick={onButtonClick}>Focus the input</button>
    </>
  );
}

Essentially, useRef is like a “box” that can hold a mutable value in its .current property. You might be familiar with refs primarily as a way to access the DOM. If you pass a ref object to React with <div ref={myRef} />, React will set its .current property to the corresponding DOM node whenever that node changes.

However, useRef() is useful for more than the ref attribute. It’s handy for keeping any mutable value around similar to how you’d use instance fields in classes. Let's understand this with an example.

If you are familiar with React Class Components, you may have noticed that a Functional Component is a React Component without render function. Everything defined in the function's body is the render function which returns JSX in the end.

This means that whenever there is change in state then all the codes in the functional component is executed. This implies if we have a instance variable inside the functional component then with every render this will be initialized with the default value. Let's prove this.Say we have an instance variable which is recording the count of stateChange after the component is mounted. At first we will write something as below -

import React, {useState} from 'react';
const child = {
  padding: '25px',
  margin: '25px',
  border: '2px solid blue'
};

const Child = (prop) => {
  console.log("fuction called....");
  let counter = 0;
  let [myState, setMyState] = useState("A");
  
  let updateState = () => {
    counter++;
    setMyState(myState + "-u-");
    console.log("counter: "+ counter);
  }

  return (
    <div style={child}>
      <div>
        <div>MyState : {myState}</div>
        <input type="button" onClick = {() => updateState()} value="Update State"></input>
      </div>
    </div>
  );
}

export default Child;

But, Here we see a problem which every stateChage counter value is 1, and the reason is simple with every render counter variable is re-assigned.

1.JPG

Requirement here is It should be incrementing with every state change. Now let's modify this instance variable to be created using useRef. And now the same retuned object will be used always and will stay closed to the Component for the full lifetime of the component.

import React, {useState, useRef} from 'react';
const child = {
  padding: '25px',
  margin: '25px',
  border: '2px solid blue'
};

const Child = (prop) => {
  console.log("fuction called....");
  let counter = useRef(0);
  let [myState, setMyState] = useState("A");
  
  let updateState = () => {
    // Now we can update the current property of Referenced object as below.
    counter.current++;
    setMyState(myState + "-u-");
    console.log("counter: "+ counter.current);
  }

  return (
    <div style={child}>
      <div>
        <div>MyState : {myState}</div>
        <input type="button" onClick = {() => updateState()} value="Update State"></input>
      </div>
    </div>
  );
}

export default Child;

Now, finally we get the expected result.

2.JPG

Last, Keep in mind that useRef doesn’t notify you when its content changes. Mutating the .current property doesn’t cause a re-render. If you want to run some code when React attaches or detaches a ref to a DOM node, you may want to use a callback ref instead.

WHEN TO USE REACT'S REF ATTRIBUTE?

But it is not always a good idea to use the ref attribute. The general rule of thumb is to avoid it. The official React documentation mentions three occasions where you can use it because you have no other choice.

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

First, you can use the ref attribute to access the DOM API (What's an API?). You can get a value of an input element yet you can also trigger methods like a focus(). It gives you control over the DOM API, for instance to use the media elements.

Second, you can use it to integrate with third-party libraries that rely on the DOM. D3.js is such an use case, because it has to hook into the DOM and it has its own DOM manipulation API. For instance, you might want to integrate a D3 component in your React component hierarchy. Therefore you can use a ref attribute as an entry point for the D3 component. You leave the React world and access the D3 world.

Last but not least, you can trigger animations imperatively on your elements.

These are the only occasions where you should use the ref attribute in your React DOM.

Discover and read more posts from DhananjayKumar
get started