Author avatar

Gaurav Singhal

Execute JavaScript after the React.js Render Method Completes

Gaurav Singhal

  • May 28, 2020
  • 9 Min read
  • 220 Views
  • May 28, 2020
  • 9 Min read
  • 220 Views
Web Development
Front End Web Development
Client-side Framework
React

Introduction

React isn't an MVC (Model View Controller) framework, but its architecture allows developers to write clean code by easily differentiating between the template, JavaScript, and styles. The render method contains the JSX template of the app comprised of all DOM elements. In order to execute JavaScript in your app, dedicated methods called lifecycle methods are used. This guide sheds more light on these methods and their use cases, allowing you to understand where to write your JavaScript after the DOM has rendered.

A React Component's Lifecycle

Every component in React goes through three phases: the mounting phase, the updating phase, and the unmounting phase. In the mounting phase, the component is created for the first time and mounted on the DOM, and the initial value of the state is set. This is followed by an updating phase where all the interactive functionalities of your app are catered to by comparing old props with new ones, updating the state, etc. Finally, the component is unmounted from the DOM and destroyed.

Component Lifecycle Methods

Throughout these phases, there are certain methods that you can tap into, called lifecycle methods. The render() takes care of the DOM elements and is invoked every time the component is mounted or updated. Thus ,any JavaScript that needs to be executed after the render method has completed can go inside two methods: ComponentDidMount() in the mounting phase and ComponentDidUpdate() in the updating phase. There are other relevant methods pertaining to these phases, but this guide will focus on these two due to their relevance to this topic.

Use Cases

The ComponentDidMount() method is usually used for initializing any third party components or plugins in your app. For instance, when you're using native CSS libraries like MaterializeCSS or Bootstrap for modals and popups, their JavaScript can be initialized inside this method. Additionally, if your component needs any initial data to display, all API calls to the server or an external database can be made here.

The ComponentDidUpdate() method is invoked after the component is updated through a well defined condition. In the absence of this condition, it will keep on invoking itself, causing an infinite loop and eventually breaking the app. Use this method if the state has changed after the first render method, and make sure it is not invoked before the first render call. If you have a profile page in your app that you want to render editable, this component can be used for updating the state and sending the updated data to the server.

Implementation and Example

Let's work through an example.

Setup

Make sure you have Nodejs and npm installed in your machine (at least version 8 or higher) along with a code editor and a web browser.

Create a new project using create-react-app:

1
npx create-react-app react-javascript
shell

Also install axios to make API calls by running this command:

1
npm i axios

Clean up the Template

Remove the logo, App.css, and all their imports from App.js. Clean out the starter template inside the App component. Your App.js should look like the code below.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import React,{Component} from 'react';
import axios from 'axios';

export default class App extends Component {
  constructor(){
    super();
   }
  
  render(){
   
    return (
      <div className="App">
             <h1>Welcome to App</h1>   
      </div>
    );
  }
}
jsx

Using componentDidMount()

Invoke componentDidMount() and call another local function inside it to handle the API call.

1
2
3
4
5
...
componentDidMount(){
    this.getUser();
  }
...
jsx

Inside the constructor, set up the state with an empty users object, which will be populated from the API's data.

1
2
3
4
5
6
 constructor(){
    super();
    this.state={
      users:[]
    }
  }
jsx

Create the async getUser() function and make an API call to get some external data. This guide uses a free demo REST API but you can also use your own here.

1
2
3
4
5
6
7
8
9
10
11
12
async getUser(){
    let usersData=await axios.get('https://reqres.in/api/users?page=2')
                    .then(res=>{
                      return res.data.data;
                    })
                    .catch(err=>{
                      console.log(err);
                    })
    this.setState({
      users:usersData
    },()=>{console.log(this.state)})
  }
jsx

Finally, output this data on the DOM by cycling through the users array.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
  render(){
    const {users}=this.state;
    return (
      <div className="App">
        {users && users.map(user=>{
          return(
            <div className="card" key={user.id}>
              <img src={user.avatar} alt="Avatar" style={{width:'auto'}}/>
              <div className="container" >
                <h4 ><b>{user.first_name}</b></h4>
                <p>{user.email}</p>
              </div>
            </div>
          )
        })}
        
      </div>
    );
  }
jsx

Your App.js should look like this:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
import React,{Component} from 'react';
import axios from 'axios';

export default class App extends Component {
  constructor(){
    super();
    this.getUser=this.getUser.bind(this);
    this.state={
      users:[]
    }
  }
  componentDidMount(){
    this.getUser();
  }
  async getUser(){
    let usersData=await axios.get('https://reqres.in/api/users?page=2')
                    .then(res=>{
                      return res.data.data;
                    })
                    .catch(err=>{
                      console.log(err);
                    })
    this.setState({
      users:usersData
    },()=>{console.log(this.state)})
  }
  render(){
    const {users}=this.state;
    return (
      <div className="App">
        {users && users.map(user=>{
          return(
            <div className="card" key={user.id}>
              <img src={user.avatar} alt="Avatar" style={{width:'auto'}}/>
              <div className="container" >
                <h4 ><b>{user.first_name}</b></h4>
                <p>{user.email}</p>
              </div>
            </div>
          )
        })}
        
      </div>
    );
  }
}
jsx

Using componentDidUpdate()

Sometimes when the stateful data changes its value and some subsequent API calls are made after the first render has invoked, componentDidUpdate() is used.

1
2
3
4
5
 componentDidUpdate(prevProps,prevState){
    if(this.props.id !== prevProps.id){
      //make an API call here and update the state
    }
  }
jsx

For example, if you want to update a list of users with a new set of users by comparing them, you can put a relevant condition inside this method and update the previous data with the new one.

Testing

Inside the root directory, run:

1
npm start

This will spin up a local development server (usually on port 3000) and you can see the dummy data on the page. Feel free to style this the way you want.

Hooks Equivalent

After React v. 16.8.0, a stable version of React Hooks was introduced inside the core API that has made developing components much easier and faster. Hooks allow us to code the same component that was earlier based on an object-oriented model as a purely functional model. The render method is replaced by a simple return statement, and a common useEffect hook is manipulated to achieve different lifecycle methods. The hooks equivalent of componentDidMount() is as follows:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
import React,{useEffect,useState} from 'react';
import axios from 'axios';

export default function App () {
  const[users,setUsers]=useState([]);

  useEffect(async()=>{
    let usersData=await axios.get('https://reqres.in/api/users?page=2')
                    .then(res=>{
                      return res.data.data;
                    })
                    .catch(err=>{
                      console.log(err);
                    })
    setUsers(usersData)
  },[])
  
    return (
      <div className="App">
        {users && users.map(user=>{
          return(
            <div className="card" key={user.id}>
              <img src={user.avatar} alt="Avatar" style={{width:'auto'}}/>
              <div className="container" >
                <h4 ><b>{user.first_name}</b></h4>
                <p>{user.email}</p>
              </div>
            </div>
          )
        })}
        
      </div>
    );
}
jsx

Conclusion

Component lifecycle methods give you a great way of handling certain core functionalities in your app. Understanding the lifecycle phases of a component is imperative to use them correctly. In this guide, you learned the most important use cases of the two most common lifecycle methods, along with their implementation in code, so as to understand how JavaScript can be written and executed after a component is added into the DOM tree.

5