# Create the react project
npx create-react-app react-lifecycle-methods
cd react-lifecycle-methods
# Create the directory for components
mkdir src/components
# Create a component file
touch src/components/Clock.js
As your application runs, React is constantly creating and deleting components in memory.
Each class
component goes through different phases in its lifecycle:
These 3 phases are:
- **I** - **Mounting** ( component creation )
- **II** - **Updating**
- **III** - **Unmounting** (when component is finally destroyed).
Lifecycle methods are special methods available in class
components, automatically called by React when our component is Mounting or Updating or Unmounting.
We place our code in the lifecycle methods in order to run it in a certain phase.
- [ ]
Lifecycle methods are special methods that are called automatically by React during the different stages of life of one component.
These methods exist only in (stateful components) class components.
They are also reffered to as lifecycle hooks. (Different than the new React Hooks API)
- [ ]
These methods are called in the following order when an instance of a component is created and inserted into the DOM:
constructor()
render()
componentDidMount()
constructor
- Example - gist
import React from "React";
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {
year: 2020
};
console.log("1 - IN CONSTRUCTOR");
}
// custom methods and lifecycle methods go after the `constructor`- e.g. `render()`
render() {
return (
<div>
<h1>Clock</h1>
</div>
);
}
}
-
We can use it to set value from the
props
in thestate
of the class component. However, this is an anti-pattern (bad practice). -
By default it must contain
super
keyword, that receivesprops
as argument fromconstructor
-
If we are setting the
state
inconstructor
we have to usethis
keyword -
We can use it to
bind()
value ofthis
to the methods -
If we don’t initialize
state
from props and we don’t bind methods, we don’t need to implement a constructor for our React component. -
[ ]
render()
- Example - gist
// ...
class Clock extends React.Component {
constructor(props) {
// ...
}
/* ▩ custom methods and lifecycle methods go after the `constructor` ▩*/
render() {
console.log("2 - IN RENDER");
{
/* ADD */
}
return (
<div>
<h1>Clock</h1>
<h2>Year</h2> {/* ADD */}
<p>{this.state.year}</p> {/* ADD */}
</div>
);
} // ⮕ After`render` is done the React component “mounts” to the DOM.
}
- The
render()
method is the next in line lifecycle method called right after theconstructor
render()
is the only required method in aclass
component- The
render()
function should be pure, meaning that it does not modify component'sstate
. - This method structures and prepares the JSX, and returns React elements.
- After the
render
is done the React component “mounts” onto the DOM.
- [ ]
componentDidMount()
- Example - gist
// ...
class Clock extends React.Component {
constructor(props) {
// ...
}
// custom methods and lifecycle methods go after the `constructor`
componentDidMount() {
// <-- ADD
/* our code to run after `render()` is finished
and component is mounted onto the DOM */
console.log('3 - IN "COMPONENT DID MOUNT"'); // <-- ADD
}
render() {
console.log("2 - IN RENDER");
return (
<div>
<h1>Clock</h1>
<h2>Year</h2>
<p>{this.state.year}</p>
</div>
);
}
// ⮕ After`render` is done the React component “mounts” to the DOM.
}
componentDidMount()
is called immediately after componentrender()
, after the component is mounted (inserted into the DOM).
- Since the
render()
method is already executed, DOM will be already present. Which means that we can reference DOM and our component insidecomponentDidMount()
.
-
We should be aware that calling
setState()
here since this will lead to re-rendering of the component (causes additional re-rendering of the component ). -
componentDidMount
should be used when it is needed to set the initial value of thestate
when the component is created, right after the first render.componentDidMount()
is commonly used to make any needed request to the API when component loads and set the data from the API to thestate
. It is as well commonly used to set values from theprops
as the initialstate
.
// ...
// ...
{
this.state.showClock
? <Clock currentYear={2020}/> {/* UPDATE - TO PASS THE PROP */}
: null
}
// ...
// ...
// ...
class Clock extends React.Component {
constructor(props) {
// ...
};
componentDidMount() { // <-- UPDATE CODE IN C.D.M
// ...
console.log('3 - IN "COMPONENT DID MOUNT"');
this.setState({ year: this.props.currentYear }); // <-- ADD SET STATE
}
- [ ]
An update phase is caused by changes of the props
or state
.
Update phase is initiated my passing new props
, setState()
or forceUpdate()
.
Mounting phase happens only once - when component is created.
Updating phase happens every time when there is a change of the state
or the props
.
render()
- Invoked by default each time an update happens (newprops
,setState
orforceUpdate
)
componentDidUpdate()
// ...
class Clock extends React.Component {
// ...
// ...
render() {
// ...
// ...
<div>
{/*
...
...
*/}
<h2>Current Time</h2> {/* <-- ADD AT THE BOTTOM */}
<p>
{ {/* <-- ADD */}
this.props.currentTime
? this.props.currentTime
: 'LOADING'
}
</p>
{/* We will pass the currentTime by clicking the button in <App /> */}
</div>
);
}
}
// ...
// ...
// CREATE A METHOD TO UPDATE TIME IN THE STATE OF App
updateTime = () => {
const currentTime = new Date().toUTCString();
this.setState({ currentTime });
};
// ...
// ...
<button onClick={this.updateTime}> UPDATE TIME </button>; // <-- ADD A BUTTON
{
this.state.showClock ? (
<Clock currentYear={2020} currentTime={this.state.currentTime} />
) : null;
}
{
/* ^ ^ ^ PASS NEW PROP ^ ^ ^ */
}
- [ ]
componentDidUpdate()
- Example - gist
// ...
class Clock extends React.Component {
constructor(props) {
// ...
}
componentDidMount() {
// ...
}
componentDidUpdate(prevProps, prevState) {
// U2 // <-- ADD
/* code to run after the update happens via
passing new `props`,
or by calling the `setState` or `forceUpdate` */
console.log('IN "COMPONENT DID UPDATE"');
}
render() {
// ...
}
}
componentDidUpdate()
is invoked only during the updating phase, immediately after the rerender()
is finished.- We shouldn’t update the state in
componentDidUpdate()
. This can cause infinite loop if the proper condition is not set, and it causes an extra re-rendering (affects component performance). componentDidUpdate()
gives us access to theprops
andstate
from when before the update was made(componentDidUpdate(prevProps, prevState)
).- In
componentDidUpdate()
can do a comparison ofprevProps
andprevState
versus currentthis.props
andthis.state
.to see what exactly changed (if anything) and then react accordingly.
Example
// Check if new props are passed
componentDidUpdate(prevProps) {
console.log('IN "COMPONENT DID UPDATE"');
// Typical usage - comparing value of the new props:
if (prevProps.currentTime !== this.props.currentTime) {
console.log(' RECEIVED NEW PROPS ! ! !');
}
}
- [ ]
componentWillUnmount()
is invoked immediately before a component is unmounted and destroyed (removed from the DOM).
Perform any necessary cleanup in this method, such as invalidating timers, canceling network requests, like for example stopping setInterval()
timers before the component gets destroyed and prevent memory leaking .
You should not call setState() in componentWillUnmount()
because the component will never be re-rendered. Once a component instance is unmounted, it will never be mounted again.
class Clock extends React.Component {
constructor(props) {
super(props);
this.state = {
year: 2020,
timerId: null, // <-- CREATE NEW PROPERTY
timer: 0, // <-- CREATE NEW PROPERTY
};
}
updateTimer = () => { // <-- CREATE NEW METHOD
this.setState({ timer: this.state.timer + 1 });
};
// UPDATE THE CODE IN THE componentDidMount()
componentDidMount() {
console.log('IN "COMPONENT DID MOUNT"');
const timerId = setInterval(this.updateTimer, 1000); // <-- CREATE AN INTERVAL
this.setState({ year: this.props.currentYear, timerId }); // <-- SET timerId
}
// ...
// ...
// ADD THE LIFECYLCLE METHOD `componentWillUnmount()`
// CLEAR THE TIMEOUT BEFORE THE COMPONENT IS DESTROYED
componentWillUnmount() { // <-- ADD
console.log('\n XXX IN "COMPONENT WILL UNMOUNT" XXX');
clearTimeout(this.state.timerID); // <-- ADD
}
render() {
// ...
// ...
<h2>Timer: {this.state.timer} </h2> {/* <-- ADD */}
The first diagram shows the most used lifecycle methods but besides these you should now that there are the other ones, maybe not as often used, but important ones.
Let’s check the extended diagram below:
Let's update each lifecycle phase including these methods:
- constructor()
- *
componentWillMount()=> getDerivedStateFromProps() - render()
- componentDidMount()
componentWillMount()
- is considered UNSAFE method. You will notice the UNSAFE
prefix added to it.
getDerivedStateFromProps()
- the next method to be executed after the constructor()
it replaces the UNSAFE_componentWillMount
)
- getDerivedStateFromProps()
- shouldComponentUpdate()
- render()
- getSnapshotBeforeUpdate()
- componentDidUpdate()
shouldComponentUpdate()
- is the only lifecycle method that returns true
or false
If it returns false
, the render()
method gets canceled.
Here you can implement some logic to stop a re-render if it’s not necessary so your app will do less work.
getSnapshotBeforeUpdate()
is invoked right before the most recently rendered output is committed to the DOM.
Any value returned by getSnapshotBeforeUpdate()
is passed as a parameter to componentDidUpdate()
.
State and Lifecycle - React Docs