Open In App

Mimicking Lifecycle Methods with Hooks in React

Last Updated : 20 Feb, 2024
Improve
Improve
Like Article
Like
Save
Share
Report

React Hooks provides a powerful way to manage state and lifecycle events in functional components. However, if you’re transitioning from class components to functional components, you might miss the familiar lifecycle methods like componentDidMount, componentDidUpdate, and componentWillUnmount.

Fortunately, you can achieve similar functionality using Hooks. Let’s explore how to mimic lifecycle methods with Hooks.

Prerequisites:

Steps To Create React Application and Installing Module:

Step 1: Create a new react app using the following command.

npx create-react-app my-react-app

Step 2: Navigate to the root directory of your project using the following command.

cd my-react-app

Project Structure:

Screenshot-2024-01-25-162642

project structure

The updated dependencies in package.json file will look like:

"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0",
"react-scripts": "5.0.1",
"web-vitals": "^2.1.4"
}

Mounting:

Mounting in React involves creating a component and rendering it onto the DOM. Here’s a concise breakdown for both class and functional components.

Mimicking constructor:

In class components, the constructor method is used for initializing state and binding event handlers. In functional components, you can achieve similar behavior using the useState Hook for state initialization and useRef Hook for storing mutable values.

Syntax:

// In Class component
class MyComponent extends Component {
constructor(props) {
super(props);
// Your constructor logic here
}
}

// In Functional component
function createInstance(param1, param2) {
return {
param1: param1,
param2: param2,
};
}
const instance = createInstance("value1", "value2");

Mimicking componentDidMount:

In class components, componentDidMount is invoked after the component is mounted and rendered. To achieve similar behavior in functional components, you can use the useEffect Hook with an empty dependency array.

Syntax:

// In Class component
class MyComponent extends React.Component {
componentDidMount = () => {
// componentDidMount logic here
}
}
// In functional component
useEffect(() => { /* componentDidMount logic */ }, []);

Mimicking render:

The render method in class components is responsible for rendering the component UI. In functional components, the main body of the component serves the same purpose.

Syntax:

// for class component
class MyClassComponent extends React.Component {
render() {
return <div>Render content here</div>;
}
}
// for functional component
const MyFunctionalComponent = () => {
<div>Render content here</div>;
}

Updating:

Whenever a component experiences alterations, it undergoes an update. These modifications can stem from changes in props or state. React furnishes built-in methods to manage updated components:

Mimicking componentDidUpdate:

componentDidUpdate is triggered whenever props or state change. In functional components, you can use useEffect with dependencies to achieve similar behavior.

Syntax:

// for class component
class MyClassComponent extends React.Component {
componentDidUpdate(prevProps) {
// componentDidUpdate logic here
}
}
// for functional component
const MyFunctionalComponent = ({ prop }) => {
useEffect(() => {
// componentDidUpdate logic here
}, [prop]);
};

Mimicking shouldComponentUpdate:

shouldComponentUpdate allows class components to optimize rendering by preventing unnecessary re-renders. In functional components, you can achieve a similar effect using the React.memo higher-order component combined with the useMemo Hook.

// for class component
class MyClassComponent extends React.Component {
shouldComponentUpdate(nextProps, nextState) {
// shouldComponentUpdate logic here
return true; // or false based on your condition
}
}
// for functional component
const MyFunctionalComponent = React.memo(({ prop }) => {
// shouldComponentUpdate logic here
});

Unmounting:

When a component is removed from the DOM, it is considered unmounted. In this scenario, only one built-in method comes into play. These component lifecycles pertain exclusively to class components. However, functional components mimic some of these lifecycle methods using React hooks, chiefly useState() and useEffect().

Mimicking componentWillUnmount:

In class components, componentWillUnmount is used for cleanup tasks before a component unmounts. With Hooks, you can return a cleanup function from useEffect.

Syntax:

// for class component
class MyClassComponent extends React.Component {
componentWillUnmount() {
// componentWillUnmount logic here
}
}
// for functional component
const MyFunctionalComponent = () => {
useEffect(() => {
return () => {
// componentWillUnmount logic here
};
}, []);
};

Regarding the constructor:

In functional components, the constructor’s role is fulfilled by useState(). Typically, the constructor initializes state values and binds the this keyword for non-lifecycle methods. It executes prior to the component’s rendering.

In the provided example, the Greeting component employs three methods in the following order:

  1. constructor(): It sets the initial state for “greeting” and binds the reference to this within the setGreeting method.
  2. render(): This method determines the content to be displayed or returned by the component. Initially, it renders a button with an event listener and an empty paragraph.
  3. Upon clicking the button:
    • setGreeting(): This updates the greeting state from an empty string to “Hello GeeksforGeeks!“, prompting a re-render of the component.
    • render(): It runs again, displaying “Hello World!” in place of the previous empty string.

For functional components, equivalent functionality can be achieved using useState():

Example: Below is an example to illustrate’s the implementation of lifecycle methods with class components in React.

Javascript




import React, { Component } from 'react';
 
class LifecycleExample extends Component {
    constructor(props) {
        super(props);
        this.state = {
            count: 0
        };
        console.log('Constructor called');
    }
 
    componentDidMount() {
        console.log('Component did mount');
        /* Simulating an increment of
        count after mounting */
        setTimeout(() => {
            this.setState({
                count: this.state.count + 1
            });
        }, 2000);
    }
 
    componentDidUpdate(prevProps, prevState) {
        console.log('Component did update');
        // Logging the state change after updating
        console.log('Previous state:', prevState);
        console.log('Current state:', this.state);
    }
 
    componentWillUnmount() {
        console.log('Component will unmount');
    }
 
    render() {
        console.log('Render method called');
        return (
            <div>
                <h1>Lifecycle Example</h1>
                <p>Count: {this.state.count}</p>
            </div>
        );
    }
}
 
export default LifecycleExample;


Start your application using the following command.

npm start

Output:

gfg38

Output

Example 2: Below is an example to illustrate’s the mimicking lifecycle methods with Hooks in React.

Javascript




import React, {
    useState,
    useEffect,
    useRef
} from 'react';
 
const ExampleComponent = () => {
    const [count, setCount] = useState(0);
    const didMountRef = useRef(false);
 
    // componentDidMount
    useEffect(() => {
        console.log('Component mounted');
        didMountRef.current = true;
 
        // componentWillUnmount
        return () => {
            console.log('Component will unmount');
        };
    }, []);
 
    // componentDidUpdate
    useEffect(() => {
        if (didMountRef.current) {
            console.log('Component updated');
 
        } else {
            didMountRef.current = true;
        }
    }, [count]); // Only run this effect when count changes
 
    // shouldComponentUpdate
    const shouldUpdateRef = useRef(true);
    useEffect(() => {
        if (shouldUpdateRef.current) {
            console.log('Component will update');
        }
        shouldUpdateRef.current = true;
    });
 
    const handleClick = () => {
        setCount(count + 1);
    };
 
    return (
        <div>
            <p>Count: {count}</p>
            <button onClick={handleClick}>Increment</button>
        </div>
    );
};
 
export default ExampleComponent;


Start your application using the following command.

npm start

Output:

gfg46

Output



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads