React Lifecycle Simplified
This post explains the concept of lifecycle methods in a React component. Think of the lifecycle phases as birth, growth, and death.
Table of contents
What is the React Lifecycle?
React lifecycle is the period it takes our application to birth, grow, and die. It refers to the life span of components during their existence. At every phase in your application, React calls the method responsible. With this method, we can manipulate our component lifecycle to gain control over the components (the state/props to pass). The React lifecycle series are Mounting, Updating, and Unmounting. Our application goes through these phases from the time we load them to the browser. It does not always take this linear path, consider all of these cases with components; A user could load your application while it is mounting, and close the application (unmounts) almost immediately without going through the updating phase. In the three phases of React Lifecycle, these methods get the job done;
Let us take an in-depth look at them;
Mounting
The birth state of your application; The mounting phase is when components are first created and rendered to the DOM.
Mounting has these methods;
- constructor ( )
- getDerivedFromProps ( )
- render ( )
- componentDidMount ( )
constructor ( )
The first method in the mounting phase handles the initialization of the state (before the component mounts to the DOM). You can likely bind event listeners with constructor( ).
constructor(props) {
super(props);
this.state= {name: “Bibi”};
}
getDerivedFromProps ( )
The getDerivedFromProps replaced the componentWillRecieveProps in the React 17. It updates the state of your component based on the value returned from props and returns a value of null when there are no changes. This method ensures that your state and props are in sync for when you need them in your application.
Props are values provided by the parent component (unidirectional flow).
static getDerivedFromProps(props, state){
return {name:props.lastname};
}
So the getDerivedFromProps( ) has its use cases during the mounting phases (where the state depends on changes made to props and other custom rare cases).
React suggests that it is better to use it sparingly as it can introduce some unknown bugs in your application. This post has it in detail
render ( )
The popular render( ) is the method that brings our JSX file to “life”. It is required for class components. This is where you would write the JSX code you want to paint to the DOM.
render(){
console.log("component rendered");
return (
<div>
<h2>This is the body component</h2>
</div>
);
}
At this stage, the render( ) method controls the rendering of components to the UI. For better optimization during the mounting phase, It is best practice to keep the render( ) pure and without side effects. It means you do not want to set state changes here.
componentDidMount ( )
The last stage of the mounting phase is called just once in a lifecycle. (after the components mount the DOM). Here you can use setState for your component. Another use case could be adding event listeners and setting timers. If you want to load data (API or network requests) when the component paints the DOM, this is the place to do it.
componentDidMount (){
setTimeout (() => {
this.setState({name: “Scott”})
}, 10000)
);
}
We use the componentDidMount() to set a timer when this component loads to the DOM.
Updating
getDerivedFromProps ( )
The first stage of the updating phase, which we discussed in the mounting phases. It checks if there are changes from the props then passes the value to the state, and returns null if there are no changes.
shouldComponentUpdate( )
shouldComponentUpdate ( nextProps, nextState) {
console.log(Loaded shouldComponentUpdate)
return null
}
It is a Boolean method (returns true or false) and checks if the components should update or rerender. (Note: The default is usually true) With the shouldComponentUpdate( ), you can perform various checks for your component to determine if you want an update or not. You could compare strings, set, and add values. The famous use case is for controlling the exact times your component will rerender. Works for performance optimization.
shouldComponentUpdate() {
return true;
// return false;
}
toggleName = () => {
this.setState({name: “Ademi”});
}
Here, if you run shouldComponentUpdate( ) with true, the component updates; with false, it does not update during the updating phase.
render ( )
The render( ) works the same here. When the value returned from the shouldComponentUpdate( ) is true, it simply paints the updated changes of the components' UI. Every time props and state change components rerender.
getSnapshotBeforeUpdate ( )
This method stores and allows us to view the previous props and state. The full syntax is like this;
getSnapshotBeforeUpdate (prevProps, prevState ) { }
Works moment before the DOM updates and after the render( ) passes the value to componentDidUpdate( ). I think the use case for the getSnapshotBeforeUpdate( ) is slim. You will not find yourself using it very often. However, a common use case is for checking current attributes of the DOM and passing the value to componentDidUpdate( ).
componentDidUpdate ( )
As its name implies, our changes have painted the DOM. It receives the previous props and states as arguments. Here we have access to the props, state, and the value returned from getSnapshotBeforeUpdate( ). Use this method to update the DOM by the values returned from props and state.
componentDidUpdate (prevProps, prevState) { }
So in the componentDidUpdate( ) method, you can call the setState() but be advised that you should wrap it in a condition that checks for changes from either the state or props. If you let it out on its own, it will run an infinite loop that will result in a sad long-lasting bug that might crash your application or worse (your system).
Unmounting
componentWillUnmount()
It is all going away.
(The death stage in the lifecycle series). It is called when the component clears from the DOM. It is a good place to set clean-ups in your application, like canceling event listeners, network/API requests, and saving progress (a game application or a course web app). You may as well not border on unmounting, but it is better to handle this phase, and it is also a nice feature to have in your lifecycle toolbox. It could be when the user closes the application from the browser tab and other ways users shut down their application.
We are almost done!
Errors
There was a problem, something broke!
The error we encounter during rendering could put our application in a broken state, the error boundary methods are ways we used to tell react to display a fallback UI instead of breaking down. These methods catch errors while rendering in the lifecycle method and the constructors of the whole tree.
The methods responsible for error catching are getDerivedStateError( ) and componentDidCatch( ).
getDerivedStateError()
The famous use case for this method is to render a fallback UI after the error is thrown.
componentDidCatch()
The famous use case for this method is to catch and log errors. Here you may add side effects.
Note: Error boundary will not catch errors outside of the lifecycle methods.
The benefit of the error boundary method is if a component encounters an error, only that component falls back to a UI and the remaining component will be unaffected. Error boundary provides a sleek way to handle errors in the application.
Conclusion
While the inception of hooks has replaced some of the react lifecycles (The updating phases – componentDidMount, componentWillUpdate, and componentWillUnmount), It is important to have a knowledge of these methods and know where they fall in a component lifecycle. It helps you understand the transitions in the browser, DOM, and our react components.
That's it! Thank you for reading. If this was helpful, consider sharing, and following me here on Hashnode, LinkedIn, and Twitter; looking forward to connecting with you!
References
Understanding React - Component Lifecycle