React component lifecycle with Hook§

elanandkumar

Anand Kumar

Posted on May 25, 2019

React component lifecycle with Hook§

In previous post, I have explained how to convert a class component into functional component so that we can leverage the hooks.
Here is the link to article:

In this post, I will help you to understand how to get the same output that we used to achieve using component lifecycles with react hooks.

I'll be covering following lifecycle methods:

  • componentWillMount
  • componentDidMount
  • componentDidUpdate
  • shouldComponentUpdate
  • componentWillUnmount

Before we start, let's get some understanding about following hooks:

  • useState
  • useEffect ### useState useState returns a stateful value and a function to update it. #### Syntax: useState syntax ### useEffect With functional component, we are not allowed to have side effects like mutations, timers, mutations or any other side effects inside the main body of the component.

So, here we have useEffect which runs after the render happens. By default, effects run after every render but there are ways to control it which we will look into it later in the article.

Syntax:

useEffect syntax

For more details on hooks or for any other hooks provided by react, look at the official documentation.

So, let's start with the component lifecycle and try to understand the replacement of the same with hooks.

Pro Tip: Do not use hooks inside any code blocks. It must be at the top level hierarchy of the functional component.

Let's see the running example of a small application. This usage react class based component and lifecycle. At the end of the article, you can check the same application created using functional component and has the similar lifecycle execution.

Let's begin.

componentWillMount

When we convert any class component to functional component, we can write the code after defining our states (if any) using useState or before the code reaches the render (jsx) part to achieve the componentWillMount behaviour. As we know the code execution happens from top to bottom.

componentDidMount

As explained before about useEffect, we can pass the second optionalParameter to achieve the componentDidMount behavior. Let's have a look at the following code snippet.

React.useEffect(()=>{
  console.log('Robot: componentDidMount');
  // ...code goes here...
  fetchData();
}, []);
Enter fullscreen mode Exit fullscreen mode

In the above code, we have blank array [] as the second argument at line 5. Why? 🤔

Well, because the second argument when provided helps react to invoke the effect only if it detects a change in any of the entries provided. This array is dependencies for the function that we pass as first argument in useEffect.

In this case, it is blank which means it is never going to detect any change and so it will invoke only once. Isn't that what componentDidMount does? Invokes only once, right?

Please note that if the second argument is not passed in useEffect, it will execute always after render.

componentDidUpdate

Let's say, we need to invoke api call again if any props changes for the component, we do it in here once the component updates. We can achieve it using useEffect. Though, this time, we need to pass an entry to the second argument.

React.useEffect(() => {
  console.log('Robot: componentWillUpdate');
  // code goes here
  fetchData();
}, [props.selectedRobotId]);
Enter fullscreen mode Exit fullscreen mode

This time, we have passed a prop selectedRobotId in the array. So, whenever this prop is going to change, the effect will run and we get the updated component.

shouldComponentUpdate

This one is a bit tricky but let me help you to understand this. As we all know, this lifecycle method helps us to control the rendering of the component by our self. Following is an example:

shouldComponentUpdate(nextProps, nextState) {
  console.log("Robot: shouldComponentUpdate");
  return (
    nextProps.selectedRobotId !== this.props.selectedRobotId ||
    nextState.loadedRobot.id !== this.state.loadedRobot.id ||
    nextState.isLoading !== this.state.isLoading
  );
}
Enter fullscreen mode Exit fullscreen mode

But, with functional component, we can not use react component lifecycle methods this way. So, how to achieve this same result?

Well, with react, we have something called React.memo. We can wrap out component with this as shown below:

export default React.memo(Robot);
Enter fullscreen mode Exit fullscreen mode

Does this look right as an alternate to shouldComponentUpdate. No.....

Ok, so here is the thing. React.memo accepts a second argument (a function) which provides the access to nextProps and prevProps. This can help us to achieve the same thing as shouldComponentUpdate.

export default React.memo(Robot, (prevProps, nextProps) => {
  console.log('Robot: shouldComponentUpdate');
  return nextProps.selectedRobotId === prevProps.selectedRobotId;
});
Enter fullscreen mode Exit fullscreen mode

There is one thing to note here. This works opposite of shouldComponentUpdate. You return true if you do not want to re-render. You return false if you want it to render.

React handles this beautifully and so the second function is only needed if you do not want a re-render for any props change. Else, let React handle it for you. :)

componentWillUnmount

Remember, in the explanation of useEffect, I mentioned about an optional return function inside the useEffect. This return function serves the purpose of cleanup.

React.useEffect(() => {
  console.log('Robot: componentDidUpdate');
  //...code goes here
  fetchData();
  return () => {
    console.log('cleaning up...');
  }
}, [props.selectedRobotId])
Enter fullscreen mode Exit fullscreen mode

The above code snippet is similar to componentDidUpdate code block except it has a return function now. So, whenever props.selectedRobotId changes, this effect runs and the return function invokes on completion of effect where we can do cleanup.
But, this is not what happens with componentWillUnmount. Right?
Ok, so to achieve the componentWillUnmount we can add one more useEffect in our code and pass the second argument as a blank array ([]). Similar to the componentDidMount but the useEffect will have a return function this time inside, which will work as componentWillUnmount.

React.useEffect(() => {
  //...code goes here
  fetchData();
  return () => {
    console.log('cleaning up...');
  }
}, [props.selectedRobotId]);

React.useEffect(() => {
  //...code goes here
  fetchData();
  return () => {
    console.log('Robot: componentWillUnmount');
  }
}, []);
Enter fullscreen mode Exit fullscreen mode

That gives us the way to do clean up at two level. One, when component updates and one when it is ready to unmount.

Summary

In this article, we covered useState and useEffect. Then we used useEffect and memo to achieve the component life cycle methods that we have with class based component.

At first, this might look confusing but do not worry. Here is the codepen for same application (shown above) but using React hooks.

Please checkout the code and practice. Also, feel free to share it or reach out to me for any questions/concerns.

Happy learning!

💖 💪 🙅 🚩
elanandkumar
Anand Kumar

Posted on May 25, 2019

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related