- Introduction
- Create React App
- Vite
- Folder Structure
- Components
- JSX
- Rendering Elements
- Props
- State
- Event Handling
- Conditional Rendering
- List and Keys
- Styling React Components
- Form Handling
- Component Lifecycle Methods
- Composition vs Inheritance
- Higher Order Component(HOC)
- Render Props
- Hooks
- Resources
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.
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.
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:-
- Easy to learn
- Creating dynamic web applications
- Reusable components
- Performance enhancement
- Cross-platform application (React native for mobile applications)
Other aspects:-
- Created and maintained by Facebook.
- More than 190k+ stars on Github and huge community.
- Most demanded skill for front-end development.
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.
Virtual DOM rerendering always faster than real DOM paint process
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
โ 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 - Getting started with vite โญโญโญ
โ Delightful React File/Directory Structure
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
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
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
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.
In React there have two types of 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;
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;
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 (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
{}
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 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;
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>
);
};
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>
);
};
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 | 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 |
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
);
}
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
const [file, setFile] = useState("");
< onClick(e => setFile(e.target.files[0]))></ button>
<img src={file ? URL.createObjectURL(file) : "default image url"}/>
// 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;
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;
- 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>
);
};
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:
- The items in your list do not have a unique id.
- The list is a static list and will not change.
- 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.
- use Material UI for Table
- use aspect ratio as a chart width and height
aspect={2 / 1}
{/_ width / height _/}
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()
}
}
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>
)}
โ 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>
);
}
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 |
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>
)
๐ฏ 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);
};
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 ๐ธ
*/
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;
-
React Hooks in Action: With Suspense and Concurrent Mode - Book by John Larsen
-
Before including
OOP
concepts in JavaScript, React usedReact.CreateClass({})
method for building UI -
After including
OOP
concepts in JavaScript, React usedReact.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
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
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
orsetInterval
andclearInterval
- 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;
The useCallback and useMemo Hooks both are similar, used for prevent unnecessary re-rendering that can improve performance.
Example - useCallback & useMemo Hook
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 usingexport 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 thanReact.memo
.
Syntax
const memorizedCallbackReturn = useCallback(() => {
setCount((prevState) => prevState + 1);
}, []);
Example
const [count, setCount] = useState(0);
const incrementByOne = useCallback(() => {
setCount((prevState) => prevState + 1);
}, []);
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() Caching expensive computations
- 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.
- 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