Skip to content

Instantly share code, notes, and snippets.

@nurmdrafi
Last active January 12, 2024 13:08
Show Gist options
  • Save nurmdrafi/ef525d3387e961655fc2e80fa0e2b283 to your computer and use it in GitHub Desktop.
Save nurmdrafi/ef525d3387e961655fc2e80fa0e2b283 to your computer and use it in GitHub Desktop.

Index

Introduction

What is React?

React is an open-source front-end Javascript library(not framework) for building user interfaces in a predictable and efficient way using declarative code. The main objective of React.js is to develop User Interfaces that improve the speed of the apps.

Why should we use React?

Component Based Architecture

React has a component based architecture, we can use reuseable components, which saves time for developers that can avoid repetition of code for a similar looked structure.

Declarative

React is declarative. That means we have to tell react what the UI look like and React will build the actual UI with its react DOM library. This is called the declarative paradigm. In that case we don't have to worry about anything, react will handle efficiently updating and rendering of the components by using Diff Algorithm.

Advantages:-

  1. Easy to learn
  2. Creating dynamic web applications
  3. Reusable components
  4. Performance enhancement
  5. Cross-platform application (React native for mobile applications)

Other aspects:-

  1. Created and maintained by Facebook.
  2. More than 190k+ stars on Github and huge community.
  3. Most demanded skill for front-end development.

What is Virtual DOM? How Virtual DOM works ? What is Reconciliation ? What is diffing algorithm?

Virtual DOM is a just copy of the Real DOM. React creates this virtual DOM synced with the Real DOM, this process is called Reconciliation.

When state changes inside a React application then React simply creates new virtual DOM and compare with the previous Virtual DOM to find out updated node efficiently by using diff algorithm.

Then finally React just update and rerender the selected node inside the Real DOM.

DOM manipulation is fast but the process of repainting is slow, if any changes happened inside DOM, it need to repaint each nodes again, overall this process is not suitable for Single Page Application.

Is Virtual DOM is slow?

Virtual DOM rerendering always faster than real DOM paint process

Are we use React only for performance?

Its true that using React we can achieve performance but this is not the main fact. The main fact is React actually increase our working efficiency, if we manipulate real DOM using vanilla Javascript we can achieve similar performance of a website but here developers also works with both DOM manipulation and state management which is more time consuming. By using React we are just focused on state management and UI managed by React itself, we don't have to worry about how efficiently UI will render.

React is not only popular for it's performance only React is famous for amazing Developers Experience

โš™ Chrome Dev Tool > Rendering > Paint Flashing

React Roadmap for 2022

image info

Create React App

โ„ Create React App - Build setup with no configuration

  • npm is a node package manager
npm install create-react-app -g
create-react-app my-app
cd my-app
npm start
  • npx is the package runner. By default npx executes <command> either from a local nodemodules/.bin, or from a central cache, if <command> is not found then simply install any packages to run <command>. _If there occurs network issues, npx failed to fetch packages.
npx create-react-app my-app
cd my-app
npm start

// Creating a TypeScript app
npx create-react-app my-app --template typescript
  • yarn is faster than npm and perform better while occurs network issues
npm install --global yarn
yarn create react-app my-app
cd my-app
yarn start

Vite

โ„ Vite - Getting started with vite โญโญโญ

Folder Structure

โ„ Delightful React File/Directory Structure

Default

my-app
โ”œโ”€โ”€ node_modules
โ”œโ”€โ”€ public
โ”‚   โ”œโ”€โ”€ favicon.ico
โ”‚   โ”œโ”€โ”€ index.html
โ”‚   โ”œโ”€โ”€ logo192.png
โ”‚   โ”œโ”€โ”€ logo512.png
โ”‚   โ”œโ”€โ”€ manifest.json
โ”‚   โ””โ”€โ”€ robots.txt
โ””โ”€โ”€ src
โ”‚   โ”œโ”€โ”€ App.css
โ”‚   โ”œโ”€โ”€ App.js
โ”‚   โ”œโ”€โ”€ App.test.js
โ”‚   โ”œโ”€โ”€ index.css
โ”‚   โ”œโ”€โ”€ index.js
โ”‚   โ”œโ”€โ”€ logo.svg
โ”‚   โ”œโ”€โ”€ serviceWorker.js
โ”‚   โ””โ”€โ”€ setupTests.js
โ”œโ”€โ”€ README.md
โ”œโ”€โ”€ package.json
โ”œโ”€โ”€ .gitignore

Standard โœ”โœ”โœ”

my-app
โ”œโ”€โ”€ .git
โ”œโ”€โ”€ node_modules
โ”œโ”€โ”€ public
โ”‚   โ”œโ”€โ”€ favicon.ico
โ”‚   โ””โ”€โ”€ index.html
โ””โ”€โ”€ src
โ”‚   โ”œโ”€โ”€ api
โ”‚   โ”‚   โ””โ”€โ”€ axios.js
โ”‚   โ”œโ”€โ”€ assets
โ”‚   โ”‚   โ”œโ”€โ”€ audios
โ”‚   โ”‚   โ”œโ”€โ”€ images
โ”‚   โ”‚   โ””โ”€โ”€ videos
โ”‚   โ”œโ”€โ”€ auth
โ”‚   โ”‚   โ”œโ”€โ”€ RequireAdmin.js
โ”‚   โ”‚   โ””โ”€โ”€ RequireAuth.js
โ”‚   โ”œโ”€โ”€ components
โ”‚   โ”‚   โ”œโ”€โ”€ Button
โ”‚   โ”‚   โ”œโ”€โ”€ Header
โ”‚   โ”‚   โ””โ”€โ”€ Footer
โ”‚   โ”œโ”€โ”€ context
โ”‚   โ”‚   โ”œโ”€โ”€ AuthContext.js
โ”‚   โ”‚   โ””โ”€โ”€ ThemeContext.js
โ”‚   โ”œโ”€โ”€ hooks
โ”‚   โ”‚   โ”œโ”€โ”€ useAxiosPrivate.js
โ”‚   โ”‚   โ””โ”€โ”€ useRefreshToken.js
โ”‚   โ”œโ”€โ”€ pages
โ”‚   โ”‚   โ”œโ”€โ”€ AboutUs
โ”‚   โ”‚   โ”œโ”€โ”€ Dashboard
โ”‚   โ”‚   โ”œโ”€โ”€ Home
โ”‚   โ”‚   โ”œโ”€โ”€ Login
โ”‚   โ”‚   โ”œโ”€โ”€ Products
โ”‚   โ”‚   โ””โ”€โ”€ Registration
โ”‚   โ”œโ”€โ”€ utils // functions
โ”‚   โ”‚   โ”œโ”€โ”€ handleFirebaseStorage.js
โ”‚   โ”‚   โ””โ”€โ”€ localStorageManagement.js
โ”‚   โ”œโ”€โ”€ App.js
โ”‚   โ”œโ”€โ”€ index.css
โ”‚   โ”œโ”€โ”€ firebase.init.js
โ”‚   โ””โ”€โ”€ index.js
โ”œโ”€โ”€ .env.local
โ”œโ”€โ”€ .gitignore
โ”œโ”€โ”€ package.json
โ”œโ”€โ”€ package-lock.json
โ””โ”€โ”€ README.md

Advanced

my-app
โ”œโ”€โ”€ .husky
โ”œโ”€โ”€ .git
โ”œโ”€โ”€ config
โ”œโ”€โ”€ node_modules
โ”œโ”€โ”€ public
โ”‚   โ”œโ”€โ”€ favicon.ico
โ”‚   โ””โ”€โ”€ index.html
โ””โ”€โ”€ src
โ”‚   โ”œโ”€โ”€ assets
โ”‚   โ”‚   โ”œโ”€โ”€ audios
โ”‚   โ”‚   โ”œโ”€โ”€ images
โ”‚   โ”‚   โ””โ”€โ”€ videos
โ”‚   โ”œโ”€โ”€ components
โ”‚   โ”‚   โ”œโ”€โ”€ Button
โ”‚   โ”‚   โ”œโ”€โ”€ Header
โ”‚   โ”‚   โ””โ”€โ”€ Footer
โ”‚   โ”œโ”€โ”€ context
โ”‚   โ”‚   โ”œโ”€โ”€ darkModeContext.ts
โ”‚   โ”‚   โ””โ”€โ”€ darkModeReducer.ts
โ”‚   โ”œโ”€โ”€ helpers
โ”‚   โ”‚   โ”œโ”€โ”€ animation.helpers.ts
โ”‚   โ”‚   โ”œโ”€โ”€ auth.helpers.ts
โ”‚   โ”œโ”€โ”€ hooks
โ”‚   โ”‚   โ”œโ”€โ”€ useAdmin.ts
โ”‚   โ”‚   โ””โ”€โ”€ useToken.ts
โ”‚   โ”œโ”€โ”€ interfaces
โ”‚   โ”œโ”€โ”€ pages
โ”‚   โ”‚   โ”œโ”€โ”€ AboutUs
โ”‚   โ”‚   โ”œโ”€โ”€ Dashboard
โ”‚   โ”‚   โ”œโ”€โ”€ Home
โ”‚   โ”‚   โ”œโ”€โ”€ Login
โ”‚   โ”‚   โ”œโ”€โ”€ Products
โ”‚   โ”‚   โ””โ”€โ”€ Registration
โ”‚   โ”œโ”€โ”€ styles
โ”‚   โ”‚   โ”œโ”€โ”€ App.css
โ”‚   โ”‚   โ””โ”€โ”€ Dark.css
โ”‚   โ”œโ”€โ”€ redux
โ”‚   โ”œโ”€โ”€ utilities
โ”‚   โ”‚   โ””โ”€โ”€ localStorageManagement.ts // functions
โ”‚   โ”œโ”€โ”€ App.ts
โ”‚   โ”œโ”€โ”€ firebase.init.ts
โ”‚   โ””โ”€โ”€ index.ts
โ”œโ”€โ”€ .env.local
โ”œโ”€โ”€ .dockerignore
โ”œโ”€โ”€ .eslintrc
โ”œโ”€โ”€ .gitignore
โ”œโ”€โ”€ .prettierignore
โ”œโ”€โ”€ .prettierrc
โ”œโ”€โ”€ Dockerfile
โ”œโ”€โ”€ package.json
โ”œโ”€โ”€ package-lock.json
โ””โ”€โ”€ README.md

Components

Component represents a part of the User Interfaces. Components also reuseable, same component can be used with different props(properties) to display different information. It can also nested inside other components as a child component. They are building blocks of any react application.

Component Types

In React there have two types of component:-

1. Stateless Functional Component:

Functional Component are literally JavaScript functions, they can optionally receive props(object properties) as input and return HTML(JSX) which describes the user interface.

import React from "react";

const Hello = (props) => {
  return (
    <div>
      <h1>Hello, {props.name}</h1>
    </div>
  );
};

export default Hello;

2. Stateful Class Component:

Class Component are basically ES6 classes, similar to functional component they can optionally receive props(object properties) as input and they must contain a render method which returns HTML(JSX). Class component can also maintain a private internal state to describe the user interface.

import React, { Component } from "react";

class Hello extends Component {
  render() {
    return (
      <div>
        <h1>Hello, {props.name}</h1>
      </div>
    );
  }
}
export default Hello;

Functional Component VS Class Component

No. Functional Component Class Component
1 Simple function, receive input as props and return JSX ES6 classes, which are advanced than a simple function but complicated
2 Use functional component as much as possible Class component are not beginner friendly, they also provide life cycle hooks
3 Absence of this keyword Includes this keyword
4 There is no render method It must have render method to returning JSX
5 Also known as stateless component, they simple input properties and display them Also known as stateful component because they have private state, which is difficult for maintenance and debugging.
6 Functional component tend to be without any complicated logic and are mainly responsible for the user interface. Class component implement complex UI logic.

JSX

โ„ React JSX in Depth

JSX (JavaScript XML) is a syntax extension to JavaScript that gives visual aid to developers by allowing them to write HTML types of codes in JavaScript, but it comes with the full power of JavaScript.

  • JSX tags have tag name, attributes, and children
  • JSX is not a necessity to write React Application, but it makes our code elegant, simple and readable
  • JSX produces React โ€œelementsโ€. by using createElement function React.createElement(component, props, ...children)
import React from "react";

const Hello = () => {
  /* 
  <div>
    Hello World
  </div>
  */
  return React.createElement("div", null, "Hello World");
};

export default Hello;
import React from "react";

const Hello = () => {
  /* 
  <div className="dummyClass">
    <h1>Hello World</h1>
  </div>
  */
  return React.createElement(
    "div",
    { className: "dummyClass" },
    React.createElement("h1", null, "Hello World")
  );
};

export default Hello;
  • Attributes in JSX elements:-

    • Example:

    • "class" is a reserved keyword in JavaScript, it becomes "className"

    • "for" is reserved for loop, it becomes "htmlFor"

    • and some other attributes like "onclick" becomes "onClick", "tabindex" becomes "tabIndex".

  • Adding Expressions into JSX by using curly braces {}

Rendering Elements

In order to render any element into the Browser DOM, we need to have a container or root DOM element. It is almost a convention to have a div element with the id=โ€rootโ€ or id=โ€appโ€ to be used as the root DOM element. Letโ€™s suppose our index.html file has the following statement inside it.

<div id="root"></div>

React Elements are immutable i.e. once an element is created it is impossible to update its children or attribute. Thus, in order to update an element, we must use the render() method several times to update the value over time. Letโ€™s see this in an example.

import React from "react";
import ReactDom from "react-dom";

const root = ReactDOM.createRoot(document.getElementById("root"));

function tick() {
  const element = (
    <div>
      <h1>Hello, world!</h1>
      <h2>It is {new Date().toLocaleTimeString()}.</h2>
    </div>
  );
  root.render(element);
}

setInterval(tick, 1000);

Props

Props

Props allow us to pass data from parent component to child component, which makes react components reuseable. Props are immutable, when data pass to child component, it will never be changed.

// Parent
import React from "react";
import Hello from ".components/Hello";

const App = () => {
  return (
    <div>
      <Hello name="Nur" />
      <Hello name="Rafe" />
    </div>
  );
};

export default App;
// Child
import React from "react";

const Hello = (props) => {
  return (
    <div>
      <h1>Hello, {props.name}</h1>
    </div>
  );
};

export default Hello;

Props Destructuring

Destructuring is ES6 features to make it possible to unpack values from arrays or properties from object into variables. In React destructuring props and state improves code readability.

import React from "react";

const Hello = ({ name, location }) => {
  return (
    <div>
      <p>
        Hello, {name} from {location}
      </p>
    </div>
  );
};

Passing Props from Child to Parent Component

import React, { useState } from "react";

const Parent = () => {
  const [count, setCount] = useState();
  return (
    <div>
      <p>Parent</p>
      <p>Count: {count}</p>
      <Child setCount={setCount} />
    </div>
  );
};

const Child = ({ setCount }) => {
  return (
    <div>
      <p>Child</p>
      <button onClick={() => setCount(1)}></button>
    </div>
  );
};

State

State

React component has a built-in state object. The state object is a place where we can store information of the component's current situation.

// Functional Component
import React from "react";

const [count, setCount] = useState(0);

const DisplayCount = () => {
  return <button onClick={() => setState(count + 1)}></button>;
};

export default DisplayCount;

Props are immutable, when data pass to child component, it will never be changed. So the solution is use component state

// Class Component
import React, { Component } from "react";

class Count extends Component {
  // step 1: create a state object and initialize
  constructor() {
    // call super method, init parent constructor method then get values
    super();
    this.state = {
      count: 0,
    };
  }
  // Updating a React componentโ€™s state is asynchronous
  increment() {
    // setState Method
    this.setState({
      count: this.state.count + 1,
    });
  }

  // If we need to update immediately, we have to use callback function
  increment() {
    // setState Method
    this.setState((prevState) => ({ count: prevState.count + 1 }));
  }

  /* In Functional Component we can achieve this by using useEffect() hook */
  render() {
    // step 2: using arrow function or bind method(before es6)
    return (
      <div>
        <h1>Count: {this.state.count}</h1>
        <button onClick={() => this.increment()}>+</button>
        /* Before ES6 */
        <button onClick={this.increment.bind(this)}>+</button>
      </div>
    );
  }
}

export default Count;

Do Not Modify State Directly This will not re-render a component:

// Wrong
this.state.count = 0;

// Correct
this.setState({ count: this.state.count + 1 });

Props VS State

Props State
Props are pass data to parent component to child component State is managed within the component
Props are just like function parameters State are like variables declared in the function body
Props are immutable State are changeable
props - Functional Components,
this.props - Class Components
useState Hook - Functional Component,
this.state - Class Components

Event Handling

Handling events with React elements is very similar to handling events on DOM elements. There are some syntax differences:

  • React events are named using camelCase, rather than lowercase.
  • With JSX we pass a function as the event handler, rather than a string.
function Form() {
  function handleSubmit(e) {
    e.preventDefault();
    console.log("You clicked submit.");
  }

  function clickHandler() {
    console.log("Button clicked")
  }

  return (
    <form onSubmit={handleSubmit}>
      <button type="submit">Submit</button>
    </form>
    // More Example
    <button onClick={clickHandler}>Click</button>
    <button onClick={() => clickHandler(id, e)}>Delete Row</button> // if we want to pass arguments we need to use wrapper function
    <button onClick={clickHandler()}>Click</button> // โŒ immediately call this function while rendering, but not working when click
  );
}

Conditional Rendering

In React, conditional rendering refers to the process of delivering elements and components based on certain conditions.

โ„ React Conditional Rendering Best Practices with 7 Different Methods

Ternary Operator

Preview Uploaded Image

const [file, setFile] = useState("");

< onClick(e => setFile(e.target.files[0]))></ button>
<img src={file ? URL.createObjectURL(file) : "default image url"}/>

Switch statement

// Home
<div className="widgets">
  /* Similar in look different in data, here, 4 types Widget components exists.
  Inside Widget component set data object by using switch method based on type.
  */
  <Widget type="user" />
  <Widget type="order" />
  <Widget type="earnings" />
  <Widget type="balance" />
</div>
// Widgets
const Widget = ({ type }) => {
  let data;

  // temporary
  const amount = 100;
  const percentage = 20;
  // Switch
  switch (type) {
    case "user":
      data = {
        title: "USERS",
        isMoney: false,
        icon: <AiOutlineUser />,
      };
      break;
    case "order":
      data = {
        title: "ORDERS",
        isMoney: false,
        icon: <AiOutlineShopping />,
      };
      break;
    case "earnings":
      data = {
        title: "EARNINGS",
        isMoney: true,
        icon: <RiMoneyDollarCircleLine />,
      };
      break;
    case "balance":
      data = {
        title: "BALANCE",
        isMoney: true,
        icon: <MdOutlineAccountBalanceWallet />,
      };
      break;
    default:
      break;
  }
  return (
    <div className="widget">
      <div className="left">
        <span className="title">{data.title}</span>
        <span className="counter">
          {data.isMoney && "$"}
          {amount}
        </span>
      </div>

      <div className="right">
        <div className="percentage positive">
          <IoIosArrowUp />
          {percentage} %
        </div>
        {data.icon}
      </div>
    </div>
  );
};

export default Widget;

Search Functionalities

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

const UsersList = () => {
  const [users, setUsers] = useState([]);
  const [term, setTerm] = useState("");
  useEffect(() => {
    const fetchUser = async () => {
      const res = await fetch("https://jsonplaceholder.typicode.com/users");
      const data = await res.json();
      setUsers(data);
      console.log(users);
    };
    fetchUser();
  }, []);

  let renderUsers = users.map((user) => <h2>{user.name}</h2>);

  let filterUsers = users
    .filter(({ name }) => {
      return name.toLowerCase().indexOf(term) >= 0;
    })
    .map((user) => <h2 key={user.id}>{user.name}</h2>);
  return (
    <div>
      <input
        type="text"
        value={term}
        onChange={(e) => setTerm(e.target.value)}
      />
      {filterUsers}
    </div>
  );
};
export default UsersList;

List and Keys

  • map method iterate each element of an array and returns modified array
  • add unique key while mapping, so that React can track each elements and update user interface efficiently
const NameList = () => {
  const names = [
    { id: 1, name: "Nur" },
    { id: 2, name: "Mohamod" },
    { id: 3, name: "Rafi" },
  ];
  return (
    <div>
      <ul>
        {names.map((name) => {
          <li key={name.id}>{name.name}</li>;
        })}
      </ul>
    </div>
  );
};

OR

const NameList = () => {
  const names = [
    { id: 1, name: "Nur" },
    { id: 2, name: "Mohamod" },
    { id: 3, name: "Rafi" },
  ];
  const nameList = names.map((name) => {
    <li key={name.id}>{name.name}</li>;
  });
  return (
    <div>
      <ul>{nameList}</ul>
    </div>
  );
};

Using Index as Key Anti-pattern

const NameList = () => {
  const persons = ["Bruce", "Clark", "Diana"];
  return (
    <div>
      <ul>
        {persons.map((name, index) => {
          <li key={index}>{name}</li>;
        })}
      </ul>
    </div>
  );
};

When to use index as a key?

This tree condition must be true for using index value as a key:

  1. The items in your list do not have a unique id.
  2. The list is a static list and will not change.
  3. The list will never be reordered of filtered

Otherwise, it will causes issues while we want to add item at the beginning or sorting items.

Styling React Components

Best Practices

  • use Material UI for Table
  • use aspect ratio as a chart width and height
    • aspect={2 / 1} {/_ width / height _/}

Conditional Rendering

Using Object Value

const data = [{ status: active, status: passive }];

const Show = () => {
  return (
    <div>
      <span className={`cellWithStatus ${data.status}`}></span>
    </div>
  );
};
.cellWithStatus {
  &.active {
    color: red;
    background-color: red; // to > rgba()
  }
  &.passive {
    color: goldenrod;
    background-color: goldenrod; // to > rgba()
  }
}

Create Dynamic Element Using Fragment

 const [user] = useAuthState(auth);
  const MenuItems = (
    <>
      <li>
        <Link to="/home">Home</Link>
      </li>
      <li>
        <Link to="/about">About</Link>
      </li>
      <li>
        <Link to="/appointment">Appointment</Link>
      </li>
      <li>
        <Link to="/reviews">Reviews</Link>
      </li>
      <li>
        <Link className="whitespace-nowrap" to="/contact">
          Contact Us
        </Link>
      </li>
      {!user && (
        <li>
          <Link to="/login">Login</Link>
        </li>
      )}

Form Handling

โ„ Controlled vs Uncontrolled Components in ReactJS - GeeksforGeeks โ„ Controlled vs. uncontrolled components in React - LogRocket

Controlled Components: In React, Controlled Components are those in which formโ€™s data is handled by React component (not DOM). It takes its current value through props and makes changes through callbacks like onClick, onChange, etc. A parent component manages its own state and passes the new values as props to the controlled component. A controlled component basically overrides the default behavior of the HTML form elements.

function App() {
  const [name, setName] = useState("");
  const [email, setEmail] = useState("");

  function onSubmit(e) {
    e.preventDefault();
    console.log("Name value: " + name);
    console.log("Email value: " + email);
  }
  return (
    <form onSubmit={(e) => onSubmit(e)}>
      <input
        type="text"
        name="name"
        value={name}
        onChange={(e) => setName(e.target.value)}
        required
      />
      <input
        type="email"
        name="email"
        value={email}
        onChange={(e) => setEmail(e.target.value)}
        required
      />
      <input type="submit" value="Submit" />
    </form>
  );
}

Uncontrolled Components: Uncontrolled Components are the components that are not controlled by the React state and are handled by the DOM (Document Object Model). To access inputs value we can use useRef() hook.

function App() {
  const nameRef = useRef();
  const emailRef = useRef();

  function onSubmit(e) {
    e.preventDefault();
    console.log("Name value: " + nameRef.current.value);
    console.log("Email value: " + emailRef.current.value);
  }
  return (
    <form onSubmit={(e) => onSubmit(e)}>
      <input type="text" name="name" ref={nameRef} required />
      <input type="email" name="email" ref={emailRef} required />
      <input type="submit" value="Submit" />
    </form>
  );
}
function App() {
  const nameRef, emailRef = useRef();

  function onSubmit(e) {
    e.preventDefault();
    console.log("Name value: " + nameRef.value);
    console.log("Email value: " + emailRef.value);
  }
  return (
    <form onSubmit={(e) => onSubmit(e)}>
      <input type="text" name="name" ref={(name) => nameRef = name} required />
      <input type="email" name="email" ref={(email) => emailRef = email} required />
      <input type="submit" value="Submit" />
    </form>
  );
}

Difference between Controlled and Uncontrolled Components:

Controlled Component Uncontrolled Component
The component is under control of the componentโ€™s state. Components are under the control of DOM.
Controlled components are predictable because the state of the form elements is handled by the component Uncontrolled components are not predictable because, during the lifecycle of a component, the form elements can lose their reference and may be changed/affected by other sources
Does not maintain its internal state Maintains its internal state
It accepts the current value as props We access the values using refs
Have better control on the form data and values Has very limited control over form values and data

Component Lifecycle Methods

React Component LifeCycle

When we create a react component, the component goes through several stages in its lifecycle. React provide us built in methods that we can override at particular stages in the life cycle. These methods do not exist in functional component but useEffect hook is partially related to the lifecycle.

https://www.youtube.com/watch?v=UbLYdbOPLe8

There has three phases:-

1. Mounting โ€“ When an instance of a component is being created and inserted into the DOM.

Methods: constructor, static getDerivedStateFromProps, render and componentDidMount

2. Update โ€“ When a component is being re-rendered as a result of changes to either its props or state.

Methods: static getDerivedStateFromProps, shouldComponentUpdate, render, getSnapshotBeforeUpdate and componentDidUpdate

3. Unmounting โ€“ When a component is being removed from the DOM

Methods: componentWillUnmount

import React, { Component } from "react";

class App extends Component {
  // initialize value before render
  constructor() {
    super(); // init parent component or super/base class constructor method then get access values
    this.state={
      count: 0;
    }
  }
  componentDidMount() {
    // when render first time
    console.log("componentDidMount: When component render first time");
  }
  componentWillUnmount(
    // when remove any component
    console.log("componentWillUnmount: Component Removed")
  )

  increment(){
    this.setState({count: this.state.count + 1})
  }
  decrement(){
    this.setState({count: this.state.count - 1})
  }
  render() {
    // render JSX
    return (
      <div>
        <h1>Count: {this.state.count}</h1>
        <button onClick={() => this.increment()}>Increment</button>
        <button onClick={() => this.decrement()}>Decrement</button>
      </div>
    );
  }
}
import React, { Component } from "react";
import Counter from "component/Counter.js"

class App extends Component {
  constructor() {
    super();
    this.state={
      count: 0;
    }
  }
  componentDidMount() {
    console.log("componentDidMount: When component render first time");
  }

  increment(){
    this.setState({count: this.state.count + 1})
  }
  render() {
    return (
      <div>
        <Counter number={this.state.count} />
        <button onClick={() => this.increment()}>Increment</button>
      </div>
    );
  }
}
import React, { Component } from "react";

class Counter extends Component {
  componentDidUpdate(prevProps, prevState) {
    if(prevProps.number !== this.props.number){
      console.log("Component Updated")
    }
  }
}
render(){
  return(
    <div>
      <h1>{this.props.number}</h1>
    </div>
  )
}

Functional Component Lifecycle Method

import React, { useEffect } from "react";

const Counter = {number} =>{
  useEffect(()=>{
    // when render first time
    componentDidMount();

    // when dependency changed
    componentDidUpdate();

    // when component removed
    // if we return a function from useEffect callback function it behaves like componentWillUnmount() method
    return () =>{
      componentWillUnmount();
    }
  }, [number]) // dependency
}
return (
  <div>
    <h1>{number}</h1>
  </div>
)

Composition vs Inheritance

๐ŸŽฏ Do not use inheritance in React

Problems with Inheritance

  • Child component dependent with Parent component, If components are not independent app will not perform well
  • Not clear info from Child component actually what does inside Parent component
  • When declare Parent component, the relation between Child and Parent is not shown
// Normally
<Parent>
  <Child />
</Parent>
  • Nested component will make this process disaster ๐Ÿ˜จ
import React from "react";

class Parent extends React.Component {

  const addEmoji = (text, emoji) => {
    `${emoji} ${text} ${emoji}`
  }
  render(override) {
    let text = "I am Parent Component"
    if(override){
      text = override;
    }
    return <div>{text}</div>;
  }
}
import Parent from "./Parent";

class Child extends Parent {
  constructor() {
    super(); // init parent component or super/base class constructor method then get access values
  }
  render() {
    const decoratedText = this.addEmoji("I am Child Component", "๐Ÿผ");
    return super.render(decoratedText);
  }
}

Solution With Composition

  • Use functional component
  • Use props rather than inheritance
  • Use conditional rendering inside Child component to get rid of fully dependent on parent component
  • Wrap Parent with Child
const Child = ({ addEmoji }) => {
  const text = "I am Child component";
  return <div>{addEmoji ? addEmoji(text, "๐Ÿ˜Ž") : text}</div>; // Independent behavior
};
const App = () => {
  return <Parent>{({ addEmoji }) => <Child addEmoji={addEmoji} />}</Parent>;
};
const Parent = ({ children }) => {
  const addEmoji = (text, emoji) => `${text} ${emoji} ${text}`;
  return children(addEmoji);
};

Higher Order Component(HOC)

A Higher Order Component is a function that takes a component as an argument and returns a new component Higher-order components are not part of the React API. It is a design pattern basically, React was inspired by higher-order functions in JavaScript.

Syntax

const NewComponent = higherOrderComponent(OriginalComponent);
const SpiderMan = withCostume(PeterParker);
/* 
here, withCostume is a HOC, it takes a normal component as an argument like PeterParker, then HOC enhanced PeterParker ability and return him as a SpiderMan ๐Ÿ•ธ
*/

1. React HOC Simple Example

2. React HOC Advanced Example

HOC - withCounter.js

// Folder Structure + (with) naming convention
// src > components > HOC > withCounter.js
import React from "react";

// ๐Ÿ•ธ step 1: declare a function which takes OriginalComponent as an argument
const withCounter = (OriginalComponent) => {
  // ๐Ÿ•ธ step 2.1: create NewComponent using class component pattern
  class NewComponent extends React.Component {
    // ๐Ÿ•ธ step 3: Copy-Paste states and methods from Original Component
    constructor() {
      super();
      this.state = {
        count: 0
      };
    }
    increment = () => {
      this.setState((prevState) => ({ count: prevState.count + 1 }));
    };
  }
  // ๐Ÿ•ธ step 2.2: return newComponent
  return NewComponent;
  // ๐Ÿ•ธ step 4: call render method and return <OriginalComponent /> with props
  render(){
    return <OriginalComponent count={this.state.count} increment={this.increment}/>
  }
};

export default withCounter;

ClickCounter.js

/* 
๐Ÿ•ธ Step 5: Here, ClickCounter.js was a class component, now we convert it to a functional component, then destructure props and use them.
*/
import React from "react";
import withCounter from "./HOC/withCounter";

const ClickCounter = ({ count, increment }) => {
  return (
    <div>
      <button onClick={increment} type="button">
        Clicked {count} times
      </button>
    </div>
  );
};
// ๐Ÿ•ธ Step 6: Finally we will export default HOC and pass ClickCounter component as an argument
export default withCounter(ClickCounter);

HoverCounter.js

import React from "react";

class HoverCounter extends React.Component {
  constructor() {
    super();
    this.state = {
      count: 0,
    };
  }
  increment = () => {
    this.setState((prevState) => ({ count: prevState.count + 1 }));
  };

  render() {
    return (
      <div>
        <button onMouseEnter={this.increment} type="button">
          Hovered {this.state.count} times
        </button>
      </div>
    );
  }
}

export default HoverCounter;

Render Props

Hooks

  • React Hooks in Action: With Suspense and Concurrent Mode - Book by John Larsen

  • Before including OOP concepts in JavaScript, React used React.CreateClass({}) method for building UI

  • After including OOP concepts in JavaScript, React used React.Component

  • Class components are fundamental of React, Functional component are introduce for improve developer experience

  • Hooks are available from React version 16.8

  • Problems before hooks

    • State Management
    • Lifecycle Methods
    • Duplicate Codes
    • Sharing Same Logic
    • Use Patterns for reduce problems (Higher Order Component, Render Props, Composite Component)
  • Hooks cannot be used inside class component

  • Hooks always declare top level of functional component

  • Hooks are used for control re-render process based on user actions

useState

Using useState hook we can store any type of value temporary at global scope. It returns array where include state variable and setState function for set/change state's value. Also we can store initial value, like: 0, "", [], {}, null. By using Redux we can store values permanently.

Syntax

const [stateVariable, setterFunction] = useState(initialValue);
const counter = () => {
  const [count, setCount] = useState(0);
  const increase = () => {
    setCount(count + 1);
  };
  return (
    <div>
      <h1>{count}</h1>
      <button onClick={increase}>Increase +</button>
    </div>
  );
};

Beware when using array or object as a initial value

// Using ...spread operator
const [todo, setTodo] = useState({
  title: "",
  description: "",
});
const [title, description] = todo;

<input
  type="text"
  value={title}
  onChange={(e) => setTodo({ ...todo, title: e.target.value })}
/>;

<input
  type="text"
  value={description}
  onChange={(e) => setTodo({ ...todo, description: e.target.value })}
/>;

useState with previous state

One click can made multiple state changes in a React application, due to performance optimization, React using Batch Update, but there is a side effect and to prevent this side effect we have to call a callback function inside setState function.

What is batching mean in React.js?

Batching means grouping multiple state updates into a single re-render.

// Best Practice, using callback function
const [count, setCount] = useState(0);

setCount((prevState) => prevState + 1);

Example - useState with previous state

useEffect

React provides the useEffect hook so that we can better control side effects and integrate them into the life cycles of our components. In React except React's core responsibilities everything are side effect.

Syntax

useEffect(() => {}, []); // param1: callback function, param2: dependency array
  • If there is [empty] dependency array then callback function will run at first time rendering
  • If there is no dependency array then callback function will run each time while rendering
  • Dependency array is used for control callback function

React's Responsibilities:-

  • Render/re-render User Interface and react to user input/actions
  • Manage State and Props

Example of Side Effects:-

  • Fetching data from any API
  • Updating the DOM
  • Measuring the width, height or position of elements in the DOM
  • Setting the page title imperatively
  • Working with timers like setTimeout or setInterval and clearInterval
  • Subscribing and Unsubscribing to services
  • Setting or getting values in local storage
  • Logging message to the console or other services

What we can do using useEffect?

  • Help us perform side effects in functional components
  • Solves all the problems of lifecycle methods in class components
  • Replaces componentDidMount(), componentDidUpdate() & componentWillUnmount()

Side Effects - Class Component

class App extends React.Component {
  state = {
    count: 0,
    date: new Date(),
  };

  // First time render
  componentDidMount() {
    const { count } = this.state;
    document.title = `Clicked ${count} times`;
    // Start Timer
    this.interval = setInterval(this.tick, 1000);
  }

  // Each time render when state changes
  componentDidUpdate() {
    const { count } = this.state;
    document.title = `Clicked ${count} times`;
  }

  // Stop Timer
  componentWillUnmount() {
    clearInterval(this.interval);
  }

  addClick() {
    this.setState((prevState) => ({ count: prevState.count + 1 }));
  }

  tick() {
    this.setState({
      date: new Date(),
    });
  }

  render() {
    const { date } = this.state;
    return (
      <div className="App">
        <p>Time: {date.toLocaleDateString()}</p>
        <button onClick={() => this.addClick()}>Click</button>
      </div>
    );
  }
}

export default App;

Side Effect - Functional Component

const App = () => {
  const [count, setCount] = useState(0);
  const [date, setDate] = useState(new Date());

  const addClick = () => {
    setCount((prevState) => prevCount + 1);
  };

  const tick = () => {
    setDate(new Date());
  };

  useEffect(() => {
    document.title = `Clicked ${count} times`;
  }, [count]);

  useEffect(() => {
    const interval = setInterval(tick, 1000);

    // Cleanup - Stop Timer
    // if we return a function from useEffect callback function it behaves like componentWillUnmount() method
    return () => {
      clearInterval(interval);
    };
  }, []);

  return (
    <div className="App">
      <p>Time: {date.toLocaleDateString()}</p>
      <button onClick={addClick}>Click</button>
    </div>
  );
};

export default App;

useCallBack & useMemo

The useCallback and useMemo Hooks both are similar, used for prevent unnecessary re-rendering that can improve performance.

Example - useCallback & useMemo Hook

useCallback

The useCallback is a react hook that returns a memoized callback when passed a function and a list of dependencies as parameters. Itโ€™s very useful when a component is passing a callback to its child component to prevent the rendering of the child component. It only changes the callback when one of its dependencies gets changed.

  • useCallback hook cached callback function's return
  • shouldComponentUpdate() method === useCallback hook
  • After passing a function as a props, that function will re-render each time, because function is a reference value, it changes reference value each time while rendering
  • We have to use useCallback hook if a component re-render after using export default React.memo(component); due to passing a function as a props
  • We can only use export default React.memo(component) when component weight is higher than React.memo.

Syntax

const memorizedCallbackReturn = useCallback(() => {
  setCount((prevState) => prevState + 1);
}, []);

Example

const [count, setCount] = useState(0);

const incrementByOne = useCallback(() => {
  setCount((prevState) => prevState + 1);
}, []);

useMemo

The useMemo is similar to useCallback hook as it accepts a function and a list of dependencies but it returns the memoized value returned by the passed function. It recalculated the value only when one of its dependencies change. It is useful to avoid expensive calculations on every render when the returned value is not going to change.

  • useMemo hook memorized a function's return value
  • useMemo is also like a Higher Order Component
const [count, setCount] = useState(0);

const isEvenOrOdd = useMemo(() => {
  let i = 0;
  while (i < 1000000000) i++; // expensive calculation
  return count % 2 === 0;
}, [count]);
const [numbers] = useState([10, 20, 30]);

const total = useMemo(
  () => numbers.reduce((acc, number) => acc + number, 0), [numbers]
);

useRef

useRef() Caching expensive computations

  1. When you need to re-use the result multiple times within a component, but you don't want to re-compute the value every time the component renders.
  2. Let's say you have a component that fetches data from an API. The API call might take a few seconds to complete, so you don't want to re-fetch the data every time the component renders. Instead, you can use useRef() to cache the result to the API call

Resources

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment