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:
React Hooks: Migrate class component to functional and use hooks
Anand Kumar ・ May 12 '19
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
### useStateuseState
returns a stateful value and a function to update it. #### 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:
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();
}, []);
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]);
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
);
}
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);
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;
});
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])
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');
}
}, []);
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!
Top comments (0)