During the creation of my first React component, I started injecting fetch calls before the class component and even within the render () method. I grunted as a result of the strange side effects of my application. As part of my research, I found a lifecycle for React called componentDidMount().
I found that calling all the APIs into componentDidMount() resolved my problem, but it raised new questions.
- What is componentDidMount() in React?
- How many times does componentDidMount() run?
- Is it safe to use async/await in componentDidMount?
The advanced React course is accessible for individuals interested in becoming skilled React developers.
What is componentDidMount()?
As the name suggests, the componentDidMount method is invoked after all the elements of the page have been rendered correctly, aka after the first render () cycle. This is the final step of the mounting process. This technique is known as "post mounting". The method is called when all the child elements and components have been mounted in the Document Object Model (DOM).
During the mounting phase of React's lifecycle, you can set up network requests or subscriptions in the componentDidMount method, but to avoid any performance issues, these requests must be unsubscribed in the componentWillUnmount method.
The example below shows a classical approach to access componentDidMount().
Code Snippet
import React, { Component } from 'react';
class App extends Component {
componentDidMount() {
// Runs after the first render() lifecycle
console.log("Did mount called");
}
render() {
console.log('Render lifecycle')
return <h1>Hello World!</h1>;
}
}
export default App;
See the output below:
- Render Lifecycle is called first means console of render function is printed.
- Did mount called (first call after the component is mounted on DOM or after completion of render)
How to Use setState in componentDidMount?
The componentDidMount() method is the perfect place for us to call the setState() method to change the state of our application. Then we can render the updated JSX data.
If you look at the code below, I've made an API call with the setTimeOut function and fetched data. So after the component has been rendered correctly, the componentDidMount() method is called, and that internally calls the fetchData() method where the state of the data is changed from "Sonia Pahuja" to "Hello World!".
Code Snippet
import React, { Component } from 'react';
class DemoLifecycle extends Component {
constructor(props){
super(props);
this.state = {
data: 'Sonia Pahuja'
}
}
fetchData(){
setTimeout(() => {
console.log('Our data is fetched');
this.setState({
data: 'Hello World!'
})
}, 1000)
}
componentDidMount(){
this.fetchData();
}
render() {
return(
<div>
{this.state.data}
</div>
)
}
}
export default DemoLifecycle;
When Dom is Initially Rendered, What Happens?
- The initial data is displayed on the DOM, i.e., the name "Sonia Pahuja".
- The componentDidMount() is called, which internally calls another function, i.e., fetchData().
- The console will display "Our data is fetched."
- This is the new state of our application. "Sonia Pahuja" is now "Hello World!".
- This will again trigger a re-render, and finally, "Hello World" will be visible on the DOM.
This is how setstate works in componentDidMount.
How Many Times Does componentDidMount() Run?
React components call componentDidMount only once by default. You can only run the component again if you delete the component or change the key prop value.
Let’s look at an example where a React component only triggers componentDidMount() once.
I have a parent component with a button to increment the counter. The counter is initially set to 0. The counter is incremented after clicking the button. The Child Component is displaying the final count.
Code Snippet
DemoLifecycle (Parent Component)
class DemoLifecycle extends Component {
constructor(props){
super(props);
this.state = {
counter: 0
}
}
componentDidMount() {
console.log('componentDidMount() lifecycle of parent called');
}
incrementHandler = () => {
this.setState(state => ({counter: state.counter + 1})
)
}
render() {
console.log('render() lifecycle - Parent');
return(
<div>
<button onClick={this.incrementHandler}>Click to Increment</button>
<ChildComp number={this.state.counter} />
</div>
)
}
}
export default DemoLifecycle;
Child Component
import React, { Component } from 'react';
class ChildComp extends React.Component {
componentDidMount() {
console.log('componentDidMount() lifecycle of child called')
}
render() {
console.log('render() lifecycle - Child');
return <h1>{this.props.number} times</h1>;
}
}
Output
The above example prints the render and shows how the componentDidMount lifecycle triggers using console.log().
At first glance, this is the order in which the methods are called.
- The parent render method is called.
- The child render method is called.
- ComponentDidMount of a child is called
- ComponentDidMount of Parent is called.
I have now changed my counter from 0 to 6 after clicking the increment button six times.
Observe that only render methods are called in the console. There is no call to ComponentDidMount. It is only called once after the initial render.
Let's take a look at how componentDidMount() could be called many times. I'm going to use the same code as the previous example, but I'm going to add a new property to the <ChildComp/> component called a key. You should now see the following output when you press the increment button.
With the help of a key prop, React will keep a watch on that component and cause a componentWillUnmount if the value changes. When the ChildComp remounts, ComponentDidMount() will be called again.
What is the Key Prop?
The key property in React is a unique property that distinguishes HTML elements or a React component in React. These values have to be very unique to the element or component. By using keys, React can recognize which items have been changed, added, or removed. A stable identity should be assigned to each element within the array.
Are you more interested in learning deeper concepts of web development? You can refer KnowledgeHut’s Web Development Course.
How to Use componentDidMount() in Functional Components?
Prior to react hooks, we used class-based components to manage a state or a lifecycle. However, functional components now have the potential to have states and lifecycle methods thanks to this new functionality.
Normally, inside a class component, componentDidMount() is utilized in the following way:
componentDidMount() {
fetch(url)
.then(response => response.json())
.then(data => this.setState())
}
Functional components didn't have access to lifecycle functions before hooks, therefore if you wish to perform an HTTP request, you'd do it like this without using componentDidMount.
const ScoreBoard= props => {
const [score, setScore] = useState([])
fetch(url)
.then(resp => resp.json())
.then(data => this.setState()
return() {
// some code
}
}
The following problems will arise as a result:
- Every time the <ScoreBoard/> is re-rendered, an HTTP request is sent, which is unlikely to be useful.
- Whenever you fetch something, the state is reset.
- Lastly, since setScore() redraws the scoreboard each time, the loop runs infinitely.
Here's where the useEffect hook comes into play. Check out the following code snippet.
const ScoreBoard = props => {
const [score, setScore] = useState([]);
useEffect(() => {
fetch(url)
.then(resp => resp.json())
.then(data => setScore(data.list))
})
return()
}
We provide a second argument in order to prevent unnecessary calls to the function, as well as the infinite loop issue.
useEffect(() => {
fetch(url)
.then(response => response.json())
.then(data => setScore(data.list))
},[])
UseEffect will behave like componentDidMount if you pass blank array i.e. [] as the second argument. It knows that since your effect is not dependent on any props or state values, it will never re-run.
By default, useEffect() runs on every component update, but by passing an array of dependents, in this example, none, it never runs again.
Let's add some dependencies and see what happens.
useEffect(() => {
fetch(url)
.then(response => response.json())
.then(data => setScore(data.list))
},[score])
Instead of passing a blank array, i.e., no dependencies, we now pass the score. When the score changes, the function will be called again, which is effectively componentDidUpdate().
Can We Use Async/Await in componentDidMount?
In React, componentDidMount is a good place to use async/await. The following are the steps for using async/await in React:
- Configure babel
- Insert the async keyword in front of componentDidMount.
- Use await in the function's body.
- Ensure that any potential errors are caught.
Code Snippet
async componentDidMount() {
const response = await fetch('https://examples.com')
const jsonData = await response.json()
this.setState({ data: jsonData })
}
Things to Remember
- componentDidMount() only runs once after the first render.
- componentDidMount() may be called multiple times if the key prop value for the component changes.
- componentDidMount method is used for handling all network requests and setting up subscriptions during the mounting phase.
- It is safe to use async/await with the componentDidMount() method.
Looking to master Python? Discover the best course to learn Python and unlock endless possibilities. Start your coding journey today!
Conclusion
We learned how to use the componentDidMount() method. We talked through how it works and several examples that will help you understand how to use it in React applications. I hope that this post has helped you understand componentDidMount().
Question / Comments? Feel free to leave them in the comments below.
Thanks for reading!
Interested in learning React JS? Check out the KnowledgeHut’s React Full Course.