Components

React components are independent and reusable block of code which returns React elements and help to create a user interface (UI).

  1. Every part of a React application is a component, which splits the UI into independent reusable code.
  2. Each  independent section is processes separately.
  3. We can easily update or change any component of an application without disturbing the rest of the application.

Components lifecycle

In React, components have a lifecycle — a set of methods and events that occur from the moment a component is created to the moment it is removed from the DOM. The lifecycle of components differs slightly between Class Components and Functional Components, especially with the introduction of Hooks.

Class Components Lifecycle

Class components in React have a set of built-in methods that you can override to run code at different points during the component’s lifecycle. These methods are grouped into three main phases: Mounting, Updating, and Unmounting.

1. Mounting (When a component is being created and inserted into the DOM):

  • constructor(): Runs when the component is created. It’s typically used to initialize state and bind event handlers.
  • static getDerivedStateFromProps(): Called before every render, both on the initial mount and when new props are received. This is used for updating the state based on changes in props.
  • render(): Required method that returns the JSX (or React.createElement) that represents the UI.
  • componentDidMount(): Called once the component is mounted (added to the DOM). It’s useful for fetching data or starting timers.

2. Updating (When a component is being re-rendered due to changes in state or props):

  • static getDerivedStateFromProps(): Called again before every render, when either the state or props change.
  • shouldComponentUpdate(): Allows you to optimize performance by deciding whether the component should re-render based on changes in state or props. By default, it returns true.
  • render(): Called again to update the UI.
  • getSnapshotBeforeUpdate(): Called right before the changes from the render are applied to the DOM. It can be used to capture information (like scroll position) before the DOM is updated.
  • componentDidUpdate(): Called after the component updates in the DOM. It receives previous props and state as arguments.

3. Unmounting (When a component is being removed from the DOM):

  • componentWillUnmount(): Called just before the component is removed from the DOM. It’s used for cleanup, like canceling network requests or clearing timers.

Functional Components Lifecycle with Hooks

Functional components, since React 16.8, can now handle lifecycle events using Hooks. The useEffect hook replaces many of the class component lifecycle methods and allows you to perform side effects in functional components.

1. Mounting (When a component is first added to the DOM):

  • useEffect(() => {...}, []): This is similar to componentDidMount() in class components. It runs once after the component mounts. The empty array [] ensures the effect only runs once.

    jsx
     
    useEffect(() => { // Code here runs once when the component mounts }, []);

2. Updating (When a component re-renders due to state or props changes):

  • useEffect(() => {...}, [dependencies]): This is like componentDidUpdate(). The code inside this hook runs after every render if any value in the dependency array changes. If you provide a list of dependencies, React will run the effect only when those dependencies change.

    jsx
     
    useEffect(() => { // Code here runs when a specific prop or state value changes }, [someValue]); // Only runs when `someValue` changes

3. Unmounting (When a component is removed from the DOM):

  • useEffect(() => { return () => {...} }, []): This is similar to componentWillUnmount() in class components. The return function is the cleanup function, which is executed when the component is unmounted or when the dependencies change.

    jsx
     
    useEffect(() => { // Code here runs when the component mounts return () => { // Code here runs when the component unmounts }; }, []);

Complete Lifecycle Map

Class ComponentFunctional Component (with Hooks)
constructor()Not needed (initialization in body)
static getDerivedStateFromProps()useEffect() (with empty dependency array for first mount)
render()Direct return of JSX (no render method)
componentDidMount()useEffect(() => {...}, [])
shouldComponentUpdate()React automatically re-renders, but you can optimize using React.memo
static getDerivedStateFromProps()useEffect() with specific dependencies
getSnapshotBeforeUpdate()useEffect() can also return a cleanup function (though no direct equivalent)
componentDidUpdate()useEffect() with dependencies (similar to componentDidUpdate)
componentWillUnmount()useEffect() cleanup function

Types of components

These are the traditional way of defining components in React. They extend from React.Component and typically use a render() method to return JSX.

Example:

jsx
 
import React, { Component } from 'react'; class Welcome extends Component { render() { return <h1>Hello, world!</h1>; } } export default Welcome;

In this example:

  • Welcome is a class component.
  • It has a render() method, which returns JSX.

These are simpler components written as JavaScript functions. They receive props as an argument and return JSX.

Example:

jsx

import React from 'react'; function Welcome(props) { return <h1>Hello, world!</h1>; }

or

const Welcome = ()=>{
return(
<>
<h1> Hello world </h1>
</>
)}

export default Welcome;

In this example:

  • Welcome is a functional component.

Difference between class and function component



1. Syntax

Class Components:

Class components are ES6 classes that extend React.Component. They require a render() method that returns JSX.

import React, { Component } from 'react';

class MyComponent extends Component { render() { return <h1>Hello, World!</h1>; } } export default MyComponent;

Function Components:

Function components are simpler JavaScript functions that return JSX directly. They do not require a render() method.

jsx

import React from 'react';

function MyComponent() { return <h1>Hello, World!</h1>; } export default MyComponent;

2. State Management

Class Components:

Class components can manage state using this.state and update it using this.setState().

jsx

class Counter extends React.Component {

constructor(props) { super(props); this.state = { count: 0 }; } increment = () => { this.setState({ count: this.state.count + 1 }); }; render() { return ( <div> <p>Count: {this.state.count}</p> <button onClick={this.increment}>Increment</button> </div> ); } }

Function Components:

Function components use Hooks (specifically, useState) to manage state.

jsx

import React, { useState } from 'react';

function Counter() { const [count, setCount] = useState(0); return ( <div> <p>Count: {count}</p> <button onClick={() => setCount(count + 1)}>Increment</button> </div> ); }

3. Lifecycle Methods

Class Components:

Class components have lifecycle methods like componentDidMount()componentDidUpdate(), and componentWillUnmount(), which are used to manage side effects and interactions with the DOM.

jsx

class MyComponent extends React.Component {

componentDidMount() { console.log('Component mounted'); } componentDidUpdate(prevProps, prevState) { console.log('Component updated'); } componentWillUnmount() { console.log('Component will unmount'); } render() { return <h1>Hello, World!</h1>; } }

Function Components:

Function components use the useEffect Hook to manage side effects and simulate lifecycle behavior. The effect runs after the component mounts, updates, and unmounts.

jsx

import React, { useEffect } from 'react';

function MyComponent() {

useEffect(() => { console.log('Component mounted'); return () => { console.log('Component will unmount'); }; }, []); // Empty dependency array makes it run only on mount and unmount return <h1>Hello, World!</h1>; }

4. Performance and Optimization

Class Components:

  • Class components can be optimized using shouldComponentUpdate() to control re-rendering.
  • If not optimized, class components might re-render unnecessarily on state or prop changes.

jsx

class MyComponent extends React.Component {

shouldComponentUpdate(nextProps, nextState) { return nextState.count !== this.state.count; } }

Function Components:

  • Function components can be optimized using React.memo(), which prevents unnecessary re-renders if the props haven’t changed.
  • State updates in function components trigger re-renders by default, but can be fine-tuned with hooks like useCallback() and useMemo().

jsx

const MyComponent = React.memo(function MyComponent(props) {

return <h1>{props.text}</h1>; });

5. Hooks

Class Components:

Class components do not use hooks. They rely on lifecycle methods, state, and other built-in React features.

Function Components:

Function components use hooks (like useStateuseEffectuseContext, etc.) to handle state, side effects, and other features that class components use lifecycle methods for.

jsx

import React, { useState, useEffect } from 'react';

function MyComponent() { const [count, setCount] = useState(0); useEffect(() => { console.log('Component mounted or updated'); }, [count]); // Runs on mount or when `count` changes return ( <div> <p>Count: {count}</p> <button onClick={() => setCount(count + 1)}>Increment</button> </div> ); }

6. Code Simplicity

Class Components:

Class components generally require more boilerplate code, especially for managing state and lifecycle methods.

jsx

class MyComponent extends React.Component { constructor(props) { super(props); this.state = { count: 0 }; } increment = () => { this.setState({ count: this.state.count + 1 }); }; render() { return ( <div> <p>Count: {this.state.count}</p> <button onClick={this.increment}>Increment</button> </div> ); } }

Function Components:

Function components are shorter and simpler, especially with hooks. There is no need for constructors, lifecycle methods, or class syntax.

import React, { useState } from 'react';

function MyComponent() { const [count, setCount] = useState(0); return ( <div> <p>Count: {count}</p> <button onClick={() => setCount(count + 1)}>Increment</button> </div> ); }

7. Ref Handling

Class Components:

In class components, you use React.createRef() to create a ref and attach it to a DOM element or component.

jsx

class MyComponent extends React.Component { constructor(props) { super(props); this.myInput = React.createRef(); } focusInput = () => { this.myInput.current.focus(); }; render() { return ( <div> <input ref={this.myInput} /> <button onClick={this.focusInput}>Focus Input</button> </div> ); } }

Function Components:

In function components, you use the useRef() hook to create a ref and attach it to a DOM element.

jsx

import React, { useRef } from 'react'; function MyComponent() { const myInput = useRef(); const focusInput = () => { myInput.current.focus(); }; return ( <div> <input ref={myInput} /> <button onClick={focusInput}>Focus Input</button> </div> ); }

Summary of Differences

Feature Class Components Function Components
Syntax ES6 class with render() method Function with direct return of JSX
State Uses this.state and this.setState() Uses useState() hook
Lifecycle Methods Uses lifecycle methods like componentDidMount()componentDidUpdate() Uses useEffect() hook for lifecycle handling
Performance Optimization Can use shouldComponentUpdate() for optimization Can use React.memo() and hooks like useCallback()
Hooks Cannot use hooks Can use hooks like useStateuseEffectuseContext, etc.
Code Simplicity More boilerplate (e.g., constructors, bindings, methods) Simpler and more concise, especially with hooks
Ref Handling Uses React.createRef() Uses useRef() hook

Conclusion:

  • Class components are traditional React components that rely on state and lifecycle methods to manage state, effects, and updates.
  • Function components, especially with the advent of Hooks (useStateuseEffect, etc.), are now the preferred way to write React components due to their simplicity, less boilerplate, and powerful state management and side effect handling.

In modern React development, function components are favored because they provide a cleaner and more concise approach to writing components.