Note: Class-based components are not widely used in modern React development, but knowledge of them can be valuable for working with older projects or answering interview questions.

Let's Explore More

Example code of Class-based Component vs Function Component.

Class-based Component

import React from 'react'
class ProfileClass extends React.Component{
    render(){
        return (
      <>
        <h1>Profile Class Test</h1>
        </>
        )
    }
}
export default ProfileClass

Functional Component

const Profile = ()=>{
    return <h1>Profile</h1>
}
export default Profile

Props in Class-Based Component

Example of receiving props in class-based component

import React from 'react'
class ProfileClass extends React.Component{
    render(){
        const {hello} = this.props // destructing (h3 tag)
        return (
      <>
        <h1>Profile Class Test</h1>
        <h2>{this.props.hello}</h2>
        <h3>{hello} </h3>
       </>
       )

    }
}
export default ProfileClass

Example of receiving props in functonal component

const Profile = (props)=>{
    return <h1>Profile {props.hello}</h1>
}
export default Profile
const Profile = ({hello})=>{
    return <h1>Profile {hello}</h1>
}
export default Profile

State in Class-Based Component

import React from 'react'

class ProfileClass extends React.Component{
    constructor(props){ //constructor method
        super(props);
        //creating State
        this.state= { count : 0 , count2:0} // we can have multiple state
    }
    render(){
        const {hello} = this.props
        return (
      <>
        <h1>Profile Class Test</h1>
        <h2>{hello}</h2>
        <h2>Count: {this.state.count}</h2>
        <button>{this.setState({count:2})}Click Here<button>
      </button>
        )
    </>
    }
}

React Lifecycle

The React component lifecycle consists of a series of methods that are invoked at different stages of a component’s existence. These stages include mounting, updating, and unmounting.

1. Mounting

This phase occurs when a component is being inserted into the DOM for the first time. The following methods are invoked in this order:

Example to understand this LifeCycle Method

import {Component} from "react";
import ProfileClass from "./ProfileClass";
class About extends Component{
    constructor(props){
        super(props);
        console.log("Parent - constructor")
    }
    componentDidMount(){
        // API Calls
        console.log("Parent- ComponentDidMount")
    }
    render(){
        console.log("Parent- render")
        return (
        <div>
            <h1>About</h1>
        </div>
    )
    }
}
export default About

Below is Output:-

Output 1

Now lets add a child component inside our About.jsx

// AboutClass.jsx
import {Component} from "react";
import ProfileClass from "./ProfileClass";
class About extends Component{
    constructor(props){
        super(props);
        console.log("Parent - constructor")
    }
    componentDidMount(){
        // API Calls
        console.log("Parent- ComponentDidMount")
    }
    render(){
        console.log("Parent- render")
        return (
        <div>
            <h1>About</h1>
            <ProfileClass name="First-Child"/>
        </div>
    )
    }
}
export default About
//ProfileClass.jsx
import React from 'react'

class ProfileClass extends React.Component{
    constructor(props){
        super(props);
        //creating State
        this.state= {
            count : 0,
            count2:1
        }
        console.log(`${this.props.name} Constructor`)
    }
    componentDidMount(){
        console.log(`${this.props.name} ComponentDidMount`)
    }
    render(){
        console.log(`${this.props.name} render`)
        const {name} = this.props
        return (
      <>
        <h1>Profile Class Test</h1>
        <h2>{name}</h2>
        <h2>Count: {this.state.count}</h2>
        <button onClick={()=>this.setState({count:2})}>Click Here</button>
      </>
        )
    }
}
export default ProfileClass

Output 2

...
render(){
return (
        <div>
            <h1>About</h1>
            <ProfileClass name="First-Child"/>
            <ProfileClass name="Second-Child"/>
        </div>
    )
}

Output 3

Note: Sometimes componentDidMount will be rendered twice. So dont panice its noting wrong with React. Its just the <strict> mode doings.

React's Two Phases of Rendering

React LifeCycle

Render Phase

Commit Phase

Let's Make an API Call

 import React from "react"

class ProfileClass extends React.Component{
    constructor(props){
        super(props)
        this.state={
           userInfo:{
            name : "",
            age: 0,
            location: "",
            avatar_url:""
           }
        }
        console.log("ChildComponent")
    }
    async componentDidMount(){
        console.log("Child - ComponentDidmount before api call")
        const response = await fetch("https://api.github.com/users/sankitdev")
        const data = await response.json()
        // console.log(data)
        this.setState({
            userInfo:data,
        })
        console.log("Child - ComponentDidmount after api call")
    }
    render(){
        console.log("childcomponent render")
        const{userInfo} = this.state
        return (
            <div>
                <h1>{userInfo.name}</h1>
                <h1>{userInfo.age}</h1>
                <h1>{userInfo.location}</h1>
                <img src={userInfo.avatar_url}/>
            </div>
        )
    }
}

export default ProfileClass

Output

Understanding the Update Cycle

Modern Approach with Hooks

Unmounting in React Components

Unmounting refers to the phase in a React component's lifecycle when the component is being removed from the DOM. This phase is important because it allows you to perform cleanup operations to avoid memory leaks or other issues.

Unmounting in Class Components

Here’s an example:

class MyComponent extends React.Component {
  componentWillUnmount() {
    // Cleanup operations
    clearInterval(this.timer);
    console.log("Component is being unmounted");
  }

  render() {
    return <div>My Component</div>;
  }
}

alt text

Never ever compare class-based components with functional components - Akshay Saini

Here are some difference of codes between class-based and functional Component

Functional Component

alt text

Class-based Component

alt text

Functional Component

alt text

Class-based Component

alt text

How Many Pages Does a SPA Have? (Website Built on React)

Unmounting in useEffect()

In React functional components, the useEffect() hook is used to manage side effects like data fetching, subscriptions, and manual DOM manipulations. When a component unmounts, it's important to clean up these side effects to prevent memory leaks and other issues.

How Unmounting Works in useEffect()

Example: Clearing a Timer

import { useEffect } from "react";

function MyComponent() {
  useEffect(() => {
    // Setup: Starting an interval timer
    const timer = setInterval(() => {
      console.log("Timer running");
    }, 1000);

    // Cleanup: Clearing the timer when the component unmounts
    return () => {
      clearInterval(timer);
      console.log("Timer cleared");
    };
  }, []); // Empty dependency array means the effect runs once and the cleanup on unmount

  return <div>My Component</div>;
}

// Note: In strict mode side Effects run two times and unmouting doesn't works properly

Why Can You Use async Before componentDidMount() but Not Before useEffect()?

componentDidMount() in Class Components

useEffect() in Functional Components

The Workaround

Key Takeaways: