Lifecycle methods in React 16
To run the code samples you will need React 16.
TL;DR: this is an overview of all the lifecycle methods in React 16, what they are used for and how they can be used in your workflow.
Introduction
React is a JavaScript library by Facebook with over 110,000 stars on GitHub. It is a declarative, efficient, and flexible framework for building user interfaces. It is really very painless to create interactive user interfaces, to build component-centric applications, which are both responsive and backward compatible. It is also currently arguably the most popular JavaScript framework out there according to the state of JS survey.
This article is for developers with basic working knowledge of React. You will be introduced to the React components lifecycle methods, where they are called, how they are used and the thought process behind their implementation.
React component lifecycle methods
React components lifecycle methods can be described as events that take place from any component’s inception to the death of that same component. The lifecycle of a React component takes place within these events that are in four categories:
- Mounting: The methods and events that take place here happen as the component is mounted in the DOM.
- Updating: Here the methods and events take place after the React component has entered the DOM.
- Un-mounting: Here the methods and events take place as they React component leaves the DOM or is unmounted from the DOM.
- Error Boundaries: Here is a special category that deals with handling or gracefully catching errors in order not to totally break your React application render.
In this post, the React lifecycle methods will be explained in the order they are called by React in the DOM.
constructor()
For React class components that are not functional components, the constructor is the very first method that gets called to action in the application’s component presentation. The constructor takes in props
as an object, and you have to call the parent class through super
in order to set access this.props
to props
``inside the class. The constructor looks like this:
class FirstComponent extends Component {
constructor(props) {
console.log("constructor is called here!");
super(props);
this.state = {
counter: 0
};
}
}
The super
call is very important and it must have the props
passed into it. It is also important to know that state can only be set inside constructors. You can also set state values, bind methods and even create refs inside the constructor.
getDerivedStateFromProps()
The very next method called after the constructor is the getDerivedStateFromProps
method, it is a static method and so you cannot use this
inside of it. It is also the last method called before the render method. It kind of has a specific use case, which is to return a state object on the initial props and set state, this can also be done with the constructor but the constructor does a lot more things aside from setting state. It is not a very frequently used method as many React developers just use the constructor instead. It takes two parameters, props and state and the syntax looks like this:
static getDerivedStateFromProps(props, state) {
console.log("getDerivedStateFromProps called here");
return null;
}
It is called on every render and it can be placed inside the constructor method.
render()
This is the most important method of any React class, the whole work that is going to appear in the DOM is done here as it outputs the JSX of your component. It is the most used React lifecycle method and it is the only required method in any React class.
render(){
console.log("render method is called here");
return <div>Hello world!</div>
}
You are not however allowed to set state inside the render method as it should be pure. Pure functions are functions without side effects, they must always return the same outputs when the same corresponding inputs are passed into them.
componentDidMount()
This method is called immediately after the render method call as soon as the component is mounted. Inside this method is where you are allowed to do all the behind the scenes work you need without the DOM. These things can range from setting state, initializing and loading data and even adding event listeners. The syntax looks like this:
componentDidMount() {
console.log("componentDidMount was called here");
}
If setState
is called inside this method, the DOM is re-rendered to reflect the modification. This method is perfect for making AJAX calls.
shouldComponentUpdate()
This is the method that is called right after the componentDidMount method
, this method does not allow you set state in it. It is useful for when you do not want your props or state changes re-rendered, it is like a bridge where you have to get permission if a component should be updated based on the props or state changes made. It returns a boolean, usually true by default. The syntax looks like this:
shouldComponentUpdate(nextProps, nextState) {
console.log("should component update is called here!");
return nextState.cars.length < this.state.cars.length;
}
It takes in two arguments, nextProps
and nextState
and with those you can you can make your return conditions for the re-render. It is advised that this method be used with care and for optimization purposes keep in mind that it can trigger re-renders.
getSnapshotBeforeUpdate()
This method is a very frequently used method, it is called just between the period a component is rendered and when it is updated in the DOM. It is a kind of screenshot of what the previous state and props looks like before updating, a genius method by React. The syntax can look like this:
getSnapshotBeforeUpdate(prevProps, prevState){
console.log("getSnapshotBeforeUpdate was called here!");
if (prevState.cars.length < this.state.cars.length) {
return { lastVehicle };
}
return null;
}
It takes two parameters, prevProps
and prevState
and it either returns a value from the conditional statement or null by default. The value returned is always passed down to the componentDidUpdate method.
componentDidUpdate()
This is the next method that gets called immediately after the getSnapshotBeforeUpdate
method, right after a DOM update. Here some logic can be set up for actions on an updated DOM. The syntax is like this:
componentDidUpdate(prevProps, prevState, snapshot) {
console.log("componentDidUpdate was called here!");
if (snapshot.lastVehicle) {
return <div> No cars left! </div>
}
}
It has three parameters, the prevProps
, prevState
and the snapshot
. The snapshot
is the value returned from the getSnapshotBeforeUpdate
method. You can set state here but it should always be inside a conditional statement.
componentWillUnmount()
This method is called just before a component is unmounted from the DOM, it is the method called right after componentDidUpdate. Here is where your clean up logic should go, clearing counters and caches, cancel API requests or removing things like event listeners. It can look like this:
componentWillUnmount(){
console.log("componentWillUnmount was called here!");
window.removeEventListener("restart");
}
As you might have guessed, you cannot set state in this method because that would automatically have to cause a re-render most times. After this, your component is gone, for good.
getDerivedStateFromError()
This is one of the two new lifecycle method used to gracefully handle errors called error boundaries. If a child component of a parent component has an error we can use this method to display an error screen. The syntax looks like this:
static getDerivedStateFromError(error) {
// Update state so the next render will show the fallback UI.
return { hasError: true };
}
render() {
if (this.state.hasError) {
// You can render any custom fallback UI
return <h1>Something went wrong.</h1>;
}
return this.props.children;
}
Here we catch a child component error and we display an error message of choice to the client gracefully instead of breaking the application or displaying a blank screen.
componentDidCatch()
This is the second lifecycle method that is a React error boundary. It enhances the capability of the first error boundary above by allowing for logging errors. The syntax looks like this:
componentDidCatch(error, info) {
console.log(info.componentStack);
}
So, in addition to showing your client a decent ‘something went wrong’ message in the user interface, you also get a platform to inform a developer inspecting the component of specific information about the error. It is mostly used in addition with the getDerivedStateFromError method.
Conclusion
You have seen all the lifecycle methods in React 16, their syntax and how they all work in the chronological order of method calls. The error boundaries are relatively new and you should make sue to incorporate them in your workflow, they have been found to be very helpful. You can see a visual representation of these methods here. Happy coding!
6 June 2019
by Lotanna Nwose