Refs and the DOM


In this article We will understand about Refs in React.

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

We have discussed about using props and state to manage the components data in React. But we have few use cases where having a reference to an element helps us to develop better react applications.

We will discuss all these use cases programmatically to get better understanding. So we will start with the first Use case.

Use Case – 1:

  

Now we want to implement this in our React Application. Here we have a textbox and one button to increment the value and one button to decrement the value. It could have been a slider as well.

Lets open index.js file from our demo-project. 

Lets create a class called as QuantityIncrement which extends React.Component class. Add the Constructor.

Lets implement render method. In render method, I will place an alert with a simple text message. Return div container from render method. Inside the Div, lets place an input whose type is text and we will place a button next to the input.

Lets call a function named as IncrementQuantity on click of this button. Lets implement this function.

Now with in this function, we have to increment the quantity value each time when user clicks on the button. 

Lets create a state object in our constructor, add a property called as quantity and initialize it to 0. We can assign this value to our input element. 

Now with in IncrementQuantity function, lets try to increment the quantity value of our state object. Now call this QuantityIncrement component and render it to our root container. 

Lets save these changes. Navigate to the browser. We have the alert and We can see a textbox followed by a button.

Now when we click on the button, we get the alert again and the value in the textbox gets incremented. 

But this has two problems right now. 

First One is for every button click, our component is getting rendered again. Resulting we are getting the alert message. We don’t want to render our component for every button click. 

The second one is now our textbox has become read only. Now if we focus on textbox and if we try to enter the custom value, we will not be able to do that. That is because our textbox is ready only. 

Open developer tools and we can spot this error. 

React is expecting us to handle onChange event on that input element.

Now how do we solve these two issues. This is where we will make use of refs in react. 

We will create a reference object and we will assign it our input element. Refs are created when a component is rendered and can be defined either in the componentDidMount() or in the constructor().

Now lets go to the constructor. Refs are created using React.createRef() method. and now we attach this to our input element using the ref attribute.

On the button click, we will access this ref instance and increment the value.

When a ref is passed to an element in render, a reference to the element becomes accessible using current attribute of the ref.

When the ref attribute is used on an HTML element, the ref created in the constructor with React.createRef() receives the underlying DOM element as its current property.

When the ref attribute is used on a custom class component, the ref object receives the instance of the component as its current and through we can access the props and the methods of that component.

Now lets go to incrementQuantity function, remove the line of code we have written earlier. 

We say this.quantityRef.current. and we access the input element value using value property. And we will increment this.

Save these changes, navigate to the browser and we can test the functionality.

As one can see we don’t get alert each time when we click on the button and we can go and enter value in the textbox and from there the increment can happen as well.

Use Case – 2:

Lets create a LogIn Component , I have the code handy and pasting it here.

class LogIn extends React.Component{

  constructor(props){

    super(props);

  }



 render(){

   alert('Test Message');

   return(

     <div>

<h2>LogIn Screen...</h2>

       <p>

         <label>UserName : <input type="text"></input></label>

       </p>

       <p>

         <label>PassWord : <input type="text"></input></label>

       </p>

       <button>LogIn</button>

     </div>

   );

 }

}

Now lets render this Component instead of our Previous Component. Save these changes, navigate to the browser. 

If we observe the output, by default focus is no-where. We want our UserName input should be focussed by default when the component is rendered. 

We can set the focus to the input element by accessing its reference. 

Lets go ahead and create the reference object and assign it to our UserName input. 

With in the componentDidMount lifecycle method, we can set the focus using our reference object.

componentDidMount(){

    this.usernameRef.current.focus();

  }

Save these changes, navigate to the browser. We can see that UserName input field is focused by default. In the same way, when user clicks on LogIn button without entering either UserName or Password, we can set the focus to that respective input on the fly.

Use Case – 3:

Now lets say we want to Video Player Component using which we can play a video or pause a video. 

I have one mp4 file placed in Assets folder which is inside src folder. This is the video We to play in our application. 

Lets create a VideoPlayer Component class and add the constructor.

Lets implement render method,

Return a div container. We will place a video element inside and we will set the width and height. 

Now we have to set the source for this Video. Now lets import the Video from the Assets folder. 

Now assign that video to src attribute of our source element and set the type as video/mp4.

Now lets place two buttons using which we will control the Play and Pause of this Video. 

Now lets create a reference to our video element. Assign this reference to our video element.

Now lets handle onClick events for both of these buttons. 

Now lets create playvideo function and inside that call play method using the reference object we have created for video element and we do the same for pause Video.

this.myVideo.current.play();

 Lets call this Component and render it to our root container. 

Save these changes. Navigate to the browser. 

We can click on Play or Pause and accordingly video gets played or paused.

The other use cases where refs can be used are :

Triggering imperative animations.

Integrating with third-party DOM libraries.

Avoid using refs for anything that can be done declaratively.

We have to be very careful on when to use Refs , when to Use Props and when to Use State.

import ReactDOM from "react-dom";

import React, { Component } from "react";

import video from '../src/assets/Draft_1.mp4';



class QuantityIncrement extends React.Component{

  constructor(props){

    super(props);

    

    this.quantityRef=React.createRef();

  }



  incrementQuantity=()=>{

    this.quantityRef.current.value++;

  }

  render(){

    alert('Text Message');

    return(

      <div>

        <p>

          <label>Enter Quantity : <input type="text" ref={this.quantityRef}></input> 

          <button onClick={this.incrementQuantity}>+</button>

          </label>

        </p>

      </div>

    )

  }

}



class LogIn extends React.Component{

  constructor(props){

    super(props);

    this.userNameRef=React.createRef();

  }



  componentDidMount(){

    this.userNameRef.current.focus();

  }

 render(){

   return(

     <div>

       <h2>LogIn Screen...</h2>

       <p>

         <label>UserName : <input type="text" ref={this.userNameRef}></input></label>

       </p>

       <p>

         <label>PassWord : <input type="text"></input></label>

       </p>

       <button>LogIn</button>

     </div>

   );

 }

}



class VideoPlayer extends React.Component{

  constructor(props){

    super(props);

    this.videoRef=React.createRef();

  }



  playVideo=()=>{

    this.videoRef.current.play();

  }



  pauseVideo=()=>{

    this.videoRef.current.pause();

  }

  render(){

    return(

      <div>

        <video ref={this.videoRef} width="300" height="200" controls>

          <source src={video} type="video/mp4"></source>

        </video>

        <div>

           <button onClick={this.playVideo}>Play</button>  

           <button onClick={this.pauseVideo}>Pause</button>  

        </div>        

      </div>

    );

  }

}
const element=<VideoPlayer></VideoPlayer>
ReactDOM.render(element,document.getElementById("root"));

Video Reference





© 2020 Pragimtech. All Rights Reserved.