The React Component Lifecycle: A Comprehensive Guide

    Tuesday, April 16, 202413 min read134 views
    The React Component Lifecycle: A Comprehensive Guide

    When we build applications with React, you must understand how the React Lifecycle works between the components. It has different phases in the implementation from opening the component to closing the component. The different phases in the lifecycle of react components are

    • Mounting Phase

    • Updation Phase

    • Unmounting phase

    I am going to make it understand the Lifecycle methods in both class-based react components and hooks-based react components. In Hooks, we are going to use useEffect() most of the time.

    Class-based

    class-based lifecycle

    Hooks-based

    Hook-based lifecycle

    Before we go to the main concept let's get to know the different types of components noted those are

    • Class-based react component

    • functional component

    • Hooks-based react component

    Class-based react Component

    • Class-based components are the traditional way of creating components in React using ES6 classes.

    • They extend the React. Component class and have a render method that returns JSX (JavaScript XML) rendered to the DOM.

    • Lifecycle methods like componentDidMount, componentDidUpdate, and componentWillUnmount are commonly used in class-based components for managing the component's lifecycle and performing side effects.

    Example

    import React, { Component } from 'react';
    
    class MyComponent extends Component {
      render() {
        return <div>Hello, World!</div>;
      }
    }

    Functional Component

    • Functional components are simpler and shorter and clearer than class-based components.

    • They are functions that take props as arguments and return the values that should be rendered to the DOM.

    • Functional components do not have lifecycle methods or internal state.

    • They are commonly used for presentational components or components that don't require any state management or lifecycle methods.

    Example

    import React from 'react';
    
    const MyComponent = (props) => {
      return <div>Hello, World!</div>;
    };

    Functional Component

    • Functional components are simpler and shorter and clearer than class-based components.

    • They are functions that take props as arguments and return the values that should be rendered to the DOM.

    • Functional components do not have lifecycle methods or internal state.

    • They are commonly used for presentational components or components that don't require any state management or lifecycle methods.

    Example

    import React from 'react';
    
    const MyComponent = (props) => {
      return <div>Hello, World!</div>;
    };

    Hooks-based react Component

    • Hooks were introduced in the React 16.8 version to allow functional components to use state and other React features.

    • useState, useEffect, useMemo, etc.. are common hooks used in functional components for managing state and performing side effects.

    • Hooks enable functional components to have local state and lifecycle features without the need for class components.

    Example

    import React, { useState, useEffect } from 'react';
    
    const MyComponent = () => {
      const [count, setCount] = useState(0);
    
      useEffect(() => {
        document.title = `Clicked ${count} times`;
      }, [count]);
    
      return (
        <div>
          <p>Clicked {count} times</p>
          <button onClick={() => setCount(count + 1)}>Click me</button>
        </div>
      );
    };

    Mounting Phase

    This phase will begin when the component is at the initial render on the page and added to the DOM (document object model). The mounting phase of the component's lifecycle method has

    • constructor method

    • getDerivedStateFromProps method

    • render method

    • componentDidMount method

    Note: The constructor, getDerivedStateFromProps and componentDidMount have the same example for hooks so the example is given at componentDidMount

    The Constructor method

    The constructor() method is called whenever you create a child component as a mounting stage, we should call super(props) before anything else it will inherit methods from the parent component. In this method, we can assign a state, send network requests, etc...

    Example

    import React, { Component } from 'react';
    
    class MyComponent extends Component {
      constructor(props) {
        super(props);
        this.state = {
          count: 0,
        };
      }
    
      handleClick() {
        // Update state when button is clicked
        this.setState(prevState => ({
          count: prevState.count + 1,
        }));
      }
    
      render() {
        return (
          <div>
            <h1>Hello, World!</h1>
            <p>Count: {this.state.count}</p>
            <button onClick={this.handleClick}>Increment</button>
          </div>
        );
      }
    }
    
    export default MyComponent;

    In the above example, we have used the mounting phase of the main lifecycle methods of the react components constructor() here by using super(props) we are inheriting the methods from the parent component after that we initiated this.state values count:0.

    Note: To initiate values in the state we don't need to use the constructor method we can also use this.state itself.

    The getDerivedStateFromProps method

    In the mounting phase, the first method that is going to execute is known as getDerivedStateFromProps is used to initialize the values to state/local-storage/redex any other store by returning values it will directly update state. If you send null that means that not updating the state.

    Note: The getDerivedStateFromProps comes under the mounting and updating phase because this method gets called for every time re-render happens.

    import React, { Component } from 'react';
    
    class SimpleComponent extends Component {
          this.state = {
          doubledValue: props.value * 2
        };
      static getDerivedStateFromProps(nextProps, prevState) {
        if (nextProps.value !== prevState.value) {
          return {
            doubledValue:  nextProps.value * 2
          };
        }
        return null;
         }
      render() {
        return (
          <div>
            <p> Value: {this.state.doubledValue}</p>
          </div>
        );
      }
    }
    
    export default SimpleComponent;

    In the above example, the state will change if the props are changed we just changed the state by using the nextProps we returned the value in getDerivedStateFromProps() to change the value in the state by using props we also returned the value null so it won't change the initial state either.

    The render() Method

    CLASS-BASED:

    the render method is a fundamental part of the component which will method is to return JSX and make the component add to the DOM. This method will be a static method implemented in every class-based react component.

    Example

    import React, { Component } from 'react';
    
    class MyComponent extends Component {
      render() {
        return (
          <div>
            <h1>Hello, World!</h1>
            <p>This is a simple React component.</p>
          </div>
        );
      }
    }
    
    export default MyComponent;

    Hooks-based

    In the hooks-based react component it works differently you just need to return JSX in normal function.

    Example

    import React from 'react';
    
    function MyComponent() {
      return (
        <div>
          <h1>Hello, World!</h1>
          <p>This is a simple</p>
        </div>
      );
    }
    
    export default MyComponent;

    The componentDidMount() method

    CLASS-BASED

    The componentDidMount() method is used to initialize the class child and the values to state/local-storage/redex any other store. When we use the class component it's very important to know about it.

    Example

    import React, { Component } from 'react';
    
    class MyComponent extends Component {
      componentDidMount() {
        console.log('Component mounted');
        fetch('https://api.example.com/data')
          .then(response => response.json())
          .then(data => {
            console.log('Data fetched:', data);
          })
          .catch(error => {
            console.error('Error fetching data:', error);
          });
      }
    
      render() {
        return (
          <div>
            <h1>Hello, World!</h1>
            <p>This is a simple </p>
          </div>
        );
      }
    }
    
    export default MyComponent;

    In the above example, we are using the mounting phase in the react component lifecycle method known as componentDidMount() inside this method we are sending network requests through fetch() when the component becomes mounted component it will stop the execution of the component at the initial stage since the method is in a mounting phase.

    HOOKS-BASED

    using the useEffect hook with empty parameters will do the same as componentDidMount() in the hook-based component lifecycle method.

    Example

    import React, { useEffect } from 'react';
    
    function MyComponent() {
      useEffect(() => {
        console.log('Component mounted');
        fetch('https://api.example.com/data')
          .then(response => response.json())
          .then(data => {
            console.log('Data fetched:', data);
          })
          .catch(error => {
            console.error('Error fetching data:', error);
          });
      }, []); 
    
      return (
        <div>
          <h1>Hello, World!</h1>
          <p>This is a simple</p>
        </div>
      );
    }
    
    export default MyComponent;

    In the above example at initial render, the useEffect() will send a network request through fetch() giving empty parameters means we are asking useEffect() to execute only as componentDidMount().

    Updation Phase

    The Updation Phase of the lifecycle method has

    • componentDidupdate method

    • shouldComponentUpdate method

    • render method

    The componentDidupdate method

    CLASS-BASED

    The componentDidupdate method is used to execute a function or to fetch data or assign values to a component's state, for those or more purposes we can use this method in class-based react components.

    Example

    import React, { Component } from 'react';
    
    class MyComponent extends Component {
      componentDidUpdate(prevProps, prevState) {
        if (this.props.someProp !== prevProps.someProp) {
          console.log('Component updated');
          fetch('https://api.example.com/updatedData')
            .then(response => response.json())
            .then(data => {
              console.log('Updated data fetched:', data);
            })
            .catch(error => {
              console.error('Error fetching updated data:', error);
            });
        }
      }
      render() {
        return (
          <div>
            <h1>Hello, World!</h1>
            <p>This is a simple</p>
          </div>
        );
      }
    }
    
    export default MyComponent;

    In the above example we have used componentDidUpdate() this method is one of the lifecycle method called the updating phase here inside the componentDidUpdate() we are comparing the prevProps to check wether the props are changed or not if changed then if the condition works we send network request by using fetch().

    HOOKS-BASED

    In hooks concept with useEffect() without dependency array it can be implemented in hooks-based react components.

    Example

    import React, { useEffect, useRef } from 'react';
    
    function MyComponent(props) {
      const prevPropsRef = useRef();
      useEffect(() => {
        prevPropsRef.current = props;
      },[]);
      const prevProps = prevPropsRef.current;
      useEffect(() => {
        if (prevProps && props.someProp !== prevProps.someProp) {
          console.log('Component updated');
          fetch('https://api.example.com/updatedData')
            .then(response => response.json())
            .then(data => {
              console.log('Updated data fetched:', data);
            })
            .catch(error => {
              console.error('Error fetching updated data:', error);
            });
        }
      }, [props.someProp, prevProps]);
    
      return (
        <div>
          <h1>Hello, World!</h1>
          <p>This is a simple</p>
        </div>
      );
    }
    
    export default MyComponent;

    In hooks to use componentDidUpdate() method in hooks we gonna use useEffect() in the above example we have used two useEffects first one is used as the mounting phase to initialize prop values to prevPropsRef.current we assigned that to const variable prevProps.

    In the second useEffect in the dependency array is the lifecycle method updating phase, we have given props.someProp and prevProps as dependency parameters so whenever the change happens the values in the dependency array will send the network request by using fetch().

    The shouldComponentUpdate method

    CLASS-BASED

    The shouldComponentUpdate() method uses a boolean value and it is used to stop re-rendering the component to stop the re-rendering we just need to return a false/null and return true to re-render but by the default value, it will be true so we don't need to use it unless we have condition to apply.

    Example

    class MyComponent extends React.Component {
      shouldComponentUpdate(nextProps, nextState) {
        if (this.props.someProp !== nextProps.someProp || this.state.someState !== nextState.someState) {
          return true; // Re-render the component
        }
        return false; // Do not re-render the component
      }
      render() {
        // Render the component based on its props and state
        return (
          <div>{this.props.someProp}</div>
        );
      }
    }

    In the above example we have used shouldComponentUpdate() this method is one of only required method in the lifecycle method called the updating phase here inside the shouldComponentUpdate() is we are comapring the nextProps and nextState then if the condition works we are sending true as asking for render it otherwise we are asking to stop rendering by returning false.

    Hooks-based

    The same method we can implement using React.memo used for the same usage in functional components, for that we just need to wrap the component inside React.memo.

    Example

    import React from 'react';
    
    const MyComponent = ({ prop1, prop2 }) => {
      return (
        <div>
          {prop1} - {prop2}
        </div>
      );
    };
    // Memoized component
    const MemoizedComponent = React.memo(MyComponent);
    export default MemoizedComponent;

    In the above example, the component is wrapped inside the React.memo It will re-render the component only if the component props (prop1 or prop2) change otherwise it won't render the component.

    The render method

    The render method gets called in the class-based component whenever the changes happen in the component state and management to implement the changed changes to JSX which the render method returns.

    Unmounting phase

    The unmounting phase of the lifecycle method has

    • componentWillunmount method

    componentWillUnmount method

    CLASS-BASED

    The componentWillUnmount() will be invoked just before the component is removed from DOM. This method is most commonly used for cleanup tasks, clearing Intervels, and canceling network requests for those purposes we use this method in class-based components.

    Example

    import React from 'react';
    
    class MyComponent extends React.Component { 
      timer = null;  
      componentWillUnmount() {
        clearInterval(this.timer);
      }  
      componentDidMount() {
        this.timer = setInterval(() => {
          console.log('Timer tick');
        }, 1000);
      }
      render() {
        return <div>MyComponent</div>;
      }
    }
    
    export default MyComponent;

    In the above example we used a class-based component here we implemented one of the lifecycle methods invoked the component lifecycle methods unMounting phase. Here we executed the componentWillUnmount() method to remove the setIntervel. As the example shows we defined the timer with a null value after that to initiate the setIntervel we used one of the lifecycle methods mounting phase componentDidMount() through which we set up the timer by using setIntervel().

    In the componentWillUnmount() we executed clearIntervel() to stop the timer since we executed inside the componentWillUnmount() it will execute the clearIntervel() just before the component exits from DOM.

    Hooks-Based

    By using the useEffect returning function inside useEffect give the same result as componentWillUnmount(). It will execute the function before the component exits from the DOM.

    Example

    import React, { useEffect } from 'react';
    
    const MyComponent = () => {
      useEffect(() => {
        const timerId = setInterval(() => {
          console.log('Timer tick');
        }, 1000);
        return () => {
          clearInterval(timerId); // Clear the timer
        };
      }, []);
      return <div>MyComponent</div>;
    };
    
    export default MyComponent;

    In the above example, we are executing the setIntervel() by initializing to const variable timerId. the setIntervel prints "Timer tick" in the console for every second.

    When the page is changed we need to stop the setIntervel() to make it stop the timerId we used to initialize the setIntervel() use timerId in clearIntervel() in return inside useEffect() after returning it setIntervel will get removed from the DOM.

    Final Thoughts :

    Understanding lifecycle of react components is very important to build efficient react applications.By exploring the lifecycle method phases as mounting, updating and unmounting phases we get to know how a component works in different phases of lifecycle methods.

    To understand how react component's lifecycle method works you must need hands on experience in class-bassed components. the three main lifecycle methods are componentDidMount(), componentDidupdate() and componentWillUnmount() main methods of lifecycle's of react components those methods we can cover in hooks-based component as useEffect().

    You can use lifecycle methods using useEffect() but it won't give you full exposure of the lifecycle of react components. So in the end both class-based and hooks-based both are important when it comes to lifecycle of react component.

    24

    Related articles

    This website uses cookies to analyze website traffic and optimize your website experience. By continuing, you agree to our use of cookies as described in our Privacy Policy.