React Lifecycle Methods and Their Equivalents in Functional Components
React is the most popular JavaScript library for building user interfaces, and it provides a set of lifecycle methods that allow us to interact with our components at different stages
Lifecycle Phases
React components go through 3 phases during the lifecycle
Class-based vs Functional Components
Class-based components were the traditional way of creating components in React. However, with the introduction of Hooks in React 16.8, each lifecycle method has an equivalent in functional components using React Hooks.
Let's create a class-based component called UserProfile and explore all of its lifecycle hooks and then we’ll see how we can use their equivalents in functional components.
import React, { Component } from 'react';
class UserProfile extends Component {
}
export default UserProfile;
Mounting Phase
Let's start with the mounting phase. This is the phase where the component is created and added to the DOM. The following lifecycle methods are called during the mounting phase:
import React, { Component } from 'react';
class UserProfile extends Component {
constructor(props) {
super(props);
this.state = { user: props.user };
}
componentDidMount() {
console.log('Component mounted');
}
render() {
return (
<div>
<h2>{this.state.user.name}</h2>
<p>{this.state.user.email}</p>
</div>
);
}
}
export default UserProfile;
Here's the equivalent functional component code for the mounting phase:
import React, { useState, useEffect } from 'react';
function UserProfile(props) {
const [user, setUser] = useState(props.user);
useEffect(() => {
console.log('Component mounted');
}, []);
return (
<div>
<h2>{user.name}</h2>
<p>{user.email}</p>
</div>
);
}
export default UserProfile;
In functional components, we don't have a constructor method. Instead, we can use the useState hook to initialize state values and perform any setup logic that we would normally do in the constructor.
The render() method is replaced by simply returning the JSX markup from the functional component.
We've used the useEffect hook to replace the componentDidMount method. We can pass an empty array [] as the second argument to useEffect to simulate componentDidMount.
Update Phase
Moving on to the update phase. This is the phase where the component's props or state change and it is re-rendered. The following lifecycle methods are called during the updating phase:
领英推荐
import React, { Component } from 'react';
class UserProfile extends Component {
constructor(props) {
super(props);
this.state = { user: props.user };
}
shouldComponentUpdate(nextProps, nextState) {
console.log('shouldComponentUpdate', nextProps, nextState);
return true;
}
componentDidUpdate(prevProps, prevState) {
console.log('Component updated');
}
render() {
return (
<div>
<h2>{this.state.user.name}</h2>
<p>{this.state.user.email}</p>
</div>
);
}
}
export default UserProfile;
Here's the equivalent functional component code for the update phase:
import React, { useState, useEffect } from 'react';
const UserProfile = (props) => {
const [user, setUser] = useState(props.user);
useEffect(() => {
console.log('Component updated');
});
return (
<div>
<h2>{user.name}</h2>
<p>{user.email}</p>
</div>
);
}
export default React.memo(UserProfile)
We have used the useEffect hook without any dependencies, so it will be called after every render to replicate the behavior of the componentDidUpdate method.
However, it is more common to pass a specific dependency array here, because having a useEffect hook without dependencies can easily cause infinite re-renders
The equivalent of shouldComponentUpdate can be using React.memo?high-order component on export, which lets you skip re-rendering a component when its props are unchanged
Unmount Phase
The unmount phase is the final phase in React lifecycle, which is triggered when a component is removed from the DOM. This can happen when a component is removed due to a parent component being removed or when the component is conditionally rendered and its condition becomes false.
In this phase, the componentWillUnmount() method is called, which allows us to perform any necessary cleanup operations such as removing event listeners or canceling network requests.
import React, { Component } from 'react';
class UserProfile extends Component {
constructor(props) {
super(props);
this.state = { user: props.user };
}
componentWillUnmount() {
console.log('Component will unmount');
}
render() {
return (
<div>
<h2>{this.state.user.name}</h2>
<p>{this.state.user.email}</p>
</div>
);
}
}
export default UserProfile;
To achieve the same functionality in a functional component, we can use the useEffect() hook with a cleanup function as follows:
import React, { useEffect } from 'react';
function MyComponent() {
const [user, setUser] = useState(props.user);
useEffect(() => {
return () => {
console.log('Component unmounted');
};
}, []);
return (
<div>
<h2>{user.name}</h2>
<p>{user.email}</p>
</div>
);
}
export default MyComponent;
Instead of componentWillUnmount we specify a cleanup function that will be called when the component is unmounted by returning a function from the useEffect() hook.
Summary
You can see that the functional component looks a lot cleaner and more concise compared to the class-based one. A lot of boilerplate code is removed, making it easier to read and understand.
React now promotes the use of functional components as they offer a simpler and more concise way of writing components. All the lifecycle hooks are available in functional components as well.
It's worth mentioning that there are other lifecycle hooks, that we haven't discussed in this tutorial (such as getDerivedStateFromProps, getSnapshotBeforeUpdate, etc). These hooks are less commonly used but still have their place in specific scenarios.
Full Stack Web Developer
9 个月Thank you