React Refs: Everything you need to know

Oct. 13, 2021, 11:32 a.m.
React · 5 min read
React Refs: Everything you need to know

Introduction

How many times has it happened when you are working on a React application and you want the parent component to interact with their children? It’s quite a 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 Refs come into play. Let’s learn more about it.

 

About React Refs

In short, React Refs 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 to use Refs? 

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.

 

Use React Refs in your application

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} />;
 }
}

 

 

Validate React forms with Refs

Let’s say you have the following simple login form where an email address and password is required:

Validate React forms with Refs

 

Creating the form with JSX

After you create a new React application, head over to your App.js file and make it a class component if it’s not already. Then return the following JSX:

<div>
   <form>
      <div>
         <label>Username:</label>
         <input type="text" />
      </div>
      <div>
         <label>Password:</label>
         <input type="password" />
      </div>
      <div>
         <button>Submit</button>
      </div>
   </form>
</div>

It’s a fairly simple form element where we have a div that contains two labels with each of the respective inputs along with a button.

 

Handling form validation with createRef()

Next, let’s write the logic to validate the form input values. Inside the class constructor(), after the super() call we create two Refs each for the username and password field as follows:

this.username = React.createRef();

this.password = React.createRef();

Make sure you have an empty formErrors object for the component state. We need this in order to store or show each error independently or simultaneously. Here’s what our constructor will look like this:

constructor(props) {
    super(props);

    this.username = React.createRef();
    this.password = React.createRef();

    this.state = {
      formErrors: []
    };
  }

Let’s now implement the validation as now we have declared the Refs above. We make a handleForm() function which takes in username and password and then checks whether the length of username is equal to zero or not. If it is, then we push a new element in the formErrors array with the respective string value you want to pass. Then we do the same for the password field by checking if the length is less than 8 characters or not:

handleForm = (username, password) => {
    const formErrors = [];

    if (username.length === 0) {
      errors.push("Empty username!");
    }

    if (password.length < 8) {
      errors.push("Make your password more than 8 charachters!");
    }

    return errors;
  };

And the other function handleFormSubmit() simply takes in the event and gets the values of username, password, and formErrors. For the formErrors, make sure you call the handleForm() passing in the required parameters. Make sure you call setState() to update the state values dynamically:

handleFormSubmit = (e) => {
    e.preventDefault();

    const username = this.username.current.value;
    const password = this.password.current.value;
    const formErrors = this.handleValidation(username, password);

    if (formErrors.length > 0) {
      this.setState({ errors });
      return;
    }
};

 

Connect Refs to the JSX markup

Back to the render() method, we first need to destructure the formErrors with the current form state:

const { formErrors } = this.state;

Next, on the onSubmit of the form element, we trigger the handleFormSubmit() function. Then we map through each error that may occur while submitting the form and inside this, we render a <p> tag which displays that error:

{formErrors.map(error => <p key={error}>{error}</p>)}

Now we need to use the defined Refs. These will of course be used for the two input elements we have. So for the username input, we add a new attribute called ref and assign it to this.username. The same can be done for the password field so that we have both of the inputs as:

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

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

That’s it! After you followed all the above steps, your code for the JSX markup should look like this:

render() {
    const { formErrors } = this.state;
    return (
      <div>
        <form onSubmit={this.handleFormSubmit}>
          {formErrors.map(error => <p key={error}>{error}</p>)}
          <div>
            <label>Username:</label>
            <input type="text" ref={this.username} />
          </div>
          <div>
            <label>Password:</label>
            <input type="password" ref={this.password} />
          </div>
          <div>
            <button>Submit</button>
          </div>
        </form>
      </div>
    );
}

 

And the class component is like this:

class App extends React.Component {
  constructor(props) {
    super(props);

    this.username = React.createRef();
    this.password = React.createRef();

    this.state = {
      formErrors: []
    };
  }


  handleFormSubmit = (e) => {
    e.preventDefault();

    const username = this.username.current.value;
    const password = this.password.current.value;
    const formErrors = this.handleValidation(username, password);

    if (formErrors.length > 0) {
      this.setState({ errors });
      return;
    }
};


  handleForm = (username, password) => {
    const formErrors = [];

    if (username.length === 0) {
      errors.push("Empty username!");
    }

    if (password.length < 8) {
      errors.push("Make your password more than 8 charachters!");
    }

    return errors;
  };

// ...

 

Conclusion

To recap, Refs make it possible to access DOM nodes directly within React. One of the most common use cases is changing the 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:






Post a Comment
Join the community

0 Comments
0
Written By
vaibhav_khulbe