Comprehensive technical documentation for modern React development.
useState: Local stateuseEffect: Side effectsuseContext: Global stateThis section dives deep into the core architectural pillars of React. Understanding these concepts is essential for building scalable applications and passing advanced viva examinations.
setState or setVar.Hooks allow functional components to use state and other React features without writing a class.
const [count, setCount] = useState(0);
[]: Runs once on mount.[prop]: Runs on mount and when prop changes.Routing enables navigation in a Single Page Application without page refreshes.
<Route path="/home" element={<Home />} /><a> tags for internal navigation./user/:id).React is a declarative, component-based JavaScript library for building user interfaces. Developed by Facebook, it revolutionized web development by introducing the Virtual DOM and a unidirectional data flow.
document.getElementById().appendChild()).
return <div>{count}</div>).
Encapsulated components that manage their own state, then composed to make complex UIs.
Data flows from parent to child via props, making the application predictable and easier to debug.
A syntax extension that allows writing HTML structure within JavaScript. Transpiled by Babel.
Built for Single Page Applications where content updates dynamically without full page reloads.
The Virtual DOM (VDOM) is an in-memory representation of the Real DOM. It is the core of React's performance.
| Feature | Functional | Class |
|---|---|---|
| Syntax | JS Function / Arrow Function | ES6 Class (extends React.Component) |
| State | useState Hook | this.state / this.setState |
| Lifecycle | useEffect Hook | componentDidMount, etc. |
| Boilerplate | Low (Modern Standard) | High (Legacy) |
Legacy Codebase: If you are working on a legacy codebase that uses class components, it might be more efficient to continue using class components rather than rewriting all of your code.
Lifecycle Methods: React class components have access to a number of lifecycle methods that are not available to function components. If you need to use one of these lifecycle methods, such as componentDidMount or componentDidUpdate, you will need to use a class component.
More Explicit: Some developers prefer the more explicit nature of class components. With class components, everything is defined in one place, making it easier to see what's going on in your code.
That being said, function components are generally considered the better choice for new React projects, as they offer better performance, simpler syntax, and easier testing. However, there are still some cases where class components might be the better option.
| Functional Components | Class Components | |
|---|---|---|
Definition |
Defined as a JavaScript function | Defined as a JavaScript class |
Stat-Management |
Uses useState and useEffect hooks to manage state and lifecycle methods | Uses state and lifecycle methods inside the class |
Props |
Passed in as an argument to the function | Passed in as a property to the class |
Lifecycle-Methods |
Uses useEffect hook to manage component lifecycle | Has access to lifecycle methods such as componentDidMount and componentDidUpdate |
Performance |
Generally faster because they do not have to create an instance of the component | Slightly slower because they have to create an instance of the component |
Syntax |
Simpler and easier to read and understand | More verbose and complex |
Code-Reusability |
Can be easily reused in other components | Cannot be easily reused in other components |
Testing |
Easier to test because they are pure functions | More difficult to test because they have state and lifecycle methods |
Refs |
Cannot use refs directly inside the component | Can use refs directly inside the component |
In React, a "state" is an object that represents the internal data of a component. It is used to manage the component's dynamic behavior and to render the component with updated information.
The data is passed within the components only.State can be modified. State can be used only in class component.
State can be changed by using the setState() method, which is provided by the React framework. When a component's state changes, React automatically re-renders the component with the updated information.
State is typically used to handle user input, control component behavior, and store component-specific data.
It's important to note that state is meant to be used only within the component it belongs to. It should not be passed down to child components as props, as this can make the code harder to maintain and debug.
React is a component-based library that divides the UI into little reusable pieces. In some cases, those components need to communicate (send data to each other) and the way to pass data between components is by using props.
“Props” is a special keyword in React, which stands for properties and is being used for passing data from one component to another.
But the important part here is that data with props are being passed in a uni-directional flow. (one way from parent to child)
Furthermore, props data is read-only, which means that data coming from the parent should not be changed by child components.
In a class component in React, props can be accessed via the this.props object. Here's an example of how to use props in a class component:
#Greeting.js
import React from 'react';
class Greeting extends React.Component {
render() {
return <h1>Hello, {this.props.name}!</h1>;
}
}
export default Greeting;
In this example, the Greeting class extends React.Component and defines a render method
that returns a greeting message with the value of the name prop passed to it.
When the Greeting component is used in another component, the name prop can be passed as an attribute, like this:
#App.js
import React from 'react';
import Greeting from './Greeting';
class App extends React.Component {
render() {
return (
<div>
<Greeting name="Alice" />
<Greeting name="Bob" />
</div>
);
}
}
export default App;
In this example, the App class extends React.Component and renders two instances of the Greeting component, each with a different name prop passed to it. When the Greeting component is rendered, it accesses the value of the name prop via this.props.name and uses it to render the greeting message.
Here's an example of how to use props in a functional component:
#Greeting.js
import React from 'react';
function Greeting(props) {
return <h1>Hello, {props.name}!</h1>;
}
export default Greeting;
In this example, the Greeting component is a simple functional component that receives a name prop and uses it to render a greeting message.
When the Greeting component is used in another component, the name prop can be passed as an attribute, like this:
#App.js
import React from 'react';
import Greeting from './Greeting';
function App() {
return (
<div>
<Greeting name="Alice" />
<Greeting name="Bob" />
</div>
);
}
export default App;
In this example, the App component is rendering two instances of the Greeting
component, each with a different name prop. When the Greeting component is rendered, it will receive the name prop
as an argument to its function, and the value of the name prop will be used to render the greeting message.
In React, you can pass data from a parent component to a child component using props.
#Parent Component:
import React from 'react';
import ChildComponent from './ChildComponent';
function ParentComponent() {
const data = {
name: 'John Doe',
age: 25,
city: 'New York',
};
return (
<div>
<ChildComponent data={data} />
</div>
);
}
export default ParentComponent;
#Child Component:
import React from 'react';
function ChildComponent(props) {
const { data } = props;
return (
<div>
<p>Name: {data.name}</p>
<p>Age: {data.age}</p>
<p>City: {data.city}</p>
</div>
);
}
export default ChildComponent;
Output:
In this example, the ParentComponent passes the data object to the ChildComponent as a prop. The ChildComponent
then receives the data object as a prop, and can access its properties using dot notation (data.name, data.age,
data.city) within the function body.
| Property | State | Props |
|---|---|---|
Source |
Defined and managed within a component | Passed from a parent component to a child |
Mutability |
Mutable and can be changed within a component | Read-only and cannot be modified |
Ownership |
Owned by the component that defines it | Owned by the parent component |
Usage |
Used to manage data within a component | Used to pass data down the component tree |
Updates |
Changes trigger a re-render of the component | Changes trigger a re-render of the component |
DefaultValues |
Must be initialized by the component itself | Can have default values defined by the parent |
Scope |
Should only be accessed and modified within component | Can be accessed by child components |
setState method.Here's an example:
class MyComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
count: 0,
};
}
handleClick = () => {
this.setState({ count: this.state.count + 1 });
};
render() {
return (
<div>
<p>Count: {this.state.count}</p>
<button onClick={this.handleClick}>Increment</button>
</div>
);
}
}
setState method of the parent component that passed the
props to the child component.Here's an example:
class ParentComponent extends React.Component {
constructor(props) {
super(props);
this.state = {
name: "John",
};
}
handleClick = () => {
this.setState({ name: "Mary" });
};
render() {
return (
<div>
<ChildComponent name={this.state.name} />
<button onClick={this.handleClick}>Change Name</button>
</div>
);
}
}
function ChildComponent(props) {
return <p>Hello {props.name}</p>;
}
In summary, to update state, you call the setState method with the new state values. To update props, you update the parent component's state, which triggers a re-render of the child component with the new prop values.
1. Update State:
Here's an example:
import React, { useState } from "react";
function MyComponent() {
const [count, setCount] = useState(0);
const handleClick = () => {
setCount(count + 1);
};
return (
<div>
<p>Count: {count}</p>
<button onClick={handleClick}>Increment</button>
</div>
);
}
2. Updating Props:
To update props from a parent component to a child component in React, the common pattern is that
the parent passes props down to the child, and if the child needs to update the parent’s state, it can call a
function passed from the parent as a prop.
Parent.jsx):In the parent component, we'll define some state and a function that updates the state. This function will be passed as a prop to the child component.
// Parent.jsx
import React, { useState } from 'react';
import Child from './Child';
const Parent = () => {
const [name, setName] = useState('John');
// Function to update the name
const updateName = (newName) => {
setName(newName);
};
return (
<div>
<h1>Parent Component</h1>
<p>Current Name: {name}</p>
{/* Passing the name and update function as props to the Child */}
<Child name={name} updateName={updateName} />
</div>
);
};
export default Parent;
Child.jsx):In the child component, we will use the props received from the parent. The child can trigger the
updateName function to update the parent state.
// Child.jsx
import React from 'react';
const Child = ({ name, updateName }) => {
// This function will be called when the button is clicked
const handleChangeName = () => {
const newName = prompt('Enter a new name:');
if (newName) {
// Call the parent function to update the name
updateName(newName);
}
};
return (
<div>
<h2>Child Component</h2>
<p>Received Name from Parent: {name}</p>
{/* Button to change the parent's name */}
<button onClick={handleChangeName}>Change Parent Name</button>
</div>
);
};
export default Child;
Parent Component (Parent.jsx):
name) with the initial value "John".updateName function is passed to the Child component as a prop.name value is also passed as a prop to the Child.Child Component (Child.jsx):
name and updateName as props.name received from the parent.updateName(newName) to update the parent's state."John" as the name.In React, you can pass data from a child component to a parent component by using callback functions.
// ParentComponent.js
import React, { useState } from 'react';
import ChildComponent from './ChildComponent';
const ParentComponent = () => {
const [childData, setChildData] = useState('');
// Callback function to receive data from the child
const receiveDataFromChild = (dataFromChild) => {
setChildData(dataFromChild);
};
return (
<div>
<h2>Parent Component</h2>
<p>Data from Child: {childData}</p>
<ChildComponent sendDataToParent={receiveDataFromChild} />
</div>
);
};
export default ParentComponent;
Call the Callback Function in the Child Component: In the child component, receive the callback function as a prop and call it when you want to pass data to the parent.
// ChildComponent.js
import React, { useState } from 'react';
const ChildComponent = ({ sendDataToParent }) => {
const [childInput, setChildInput] = useState('');
const handleChange = (e) => {
setChildInput(e.target.value);
};
const sendDataToParentOnClick = () => {
// Call the callback function with the data
sendDataToParent(childInput);
};
return (
<div>
<input type="text" value={childInput} onChange={handleChange} />
<button onClick={sendDataToParentOnClick}>Send Data to Parent</button>
</div>
);
};
export default ChildComponent;
In this example, the ParentComponent passes the receiveDataFromChild function to the
ChildComponent as the prop sendDataToParent. When the user enters data in the input
field in the ChildComponent and clicks the button, the sendDataToParentOnClick function
is called, and it invokes the callback function provided by the parent, passing the data from the child to the
parent.
import React, { useState } from 'react';
function Example() {
const [showText, setShowText] = useState(false);
const handleClick = () => {
setShowText(!showText);
};
return (
<div>
<button onClick={handleClick}>Toggle Text</button>
{showText && <p>Some text to show when button is clicked</p>}
</div>
);
}
export default Example;
Output:
In this example, we use the useState hook to create a boolean state variable called showText.
The initial value is false, which means the text won't be shown initially.
We also define a function called handleClick that toggles the value of showText
between true and false.
In the return statement, we render a button with an onClick event listener that calls
handleClick when clicked.
We also use a conditional statement to render the text only when showText is true. If
showText is false, the text won't be rendered.
When the user clicks the button, the handleClick function is called, which toggles the value of showText. This causes the component to re-render, and the text will be shown or hidden based on the new value of showText.
Note that the conditional statement used here is a shorthand way to write an if statement. The expression {
showText && <p>Some text to show when button is clicked</p> } means
"if showText is true, render the <p> element; otherwise, render nothing".
There are several techniques for performing conditional rendering in React:
function MyComponent(props) {
if (props.isLoggedIn) {
return <p>Welcome back!</p>;
} else {
return <p>Please log in.</p>;
}
}
function MyComponent(props) {
return (
<div>
{props.isMember ? <p>Welcome, member!</p> : <p>Please sign up.</p>}
</div>
);
}
function MyComponent(props) {
return (
<div>
{props.hasData &&
<ul>
{props.data.map(item => <li key={item.id}>{item.name}</li>)}
</ul>
}
</div>
);
}
function MyComponent(props) {
switch (props.status) {
case 'loading':
return <p>Loading...</p>;
case 'error':
return <p>Error: {props.errorMessage}</p>;
case 'success':
return <p>Success!</p>;
default:
return null;
}
}
import React, { Component } from "react";
class ConditionalRenderingExample extends Component {
constructor() {
super();
this.state = {
isLoggedIn: false
};
}
render() {
// Example of conditional rendering
if (this.state.isLoggedIn) {
return <p>Welcome, User!</p>;
} else {
return <p>Please log in.</p>;
}
}
}
export default ConditionalRenderingExample;
In this example, the ConditionalRenderingExample class component has a state property
isLoggedIn that is initially set to false. The render method uses an
if statement to conditionally render different content based on the value of isLoggedIn.
If isLoggedIn is true, it renders a welcome message; otherwise, it renders a login
prompt.
You can also use the ternary operator for more concise syntax:
import React, { Component } from "react";
class ConditionalRenderingExample extends Component {
constructor() {
super();
this.state = {
isLoggedIn: false
};
}
render() {
return this.state.isLoggedIn ? <p>Welcome, User!</p> : <p>Please log in.</p>;
}
}
export default ConditionalRenderingExample;
In this case, the ternary operator is used to achieve the same result as the if statement in a more
compact way.
setState/setCount).Class components have specific methods that run at different stages of a component's life.
Constructor() method is called when the component is initiated and it’s the best place to initialize our state. The constructor method takes props as an argument and starts by calling super(props) before anything else.
import React, { Component } from 'react'
export default class App extends Component {
constructor(props){
super(props)
this.state = {
name: 'Constructor Method'
}
}
render() {
return (
<div>
<p> This is a {this.state.name}</p>
</div>
)
}
}
render()
Note : render() will not be invoked if shouldComponentUpdate() returns false.
componentDidMount() The most common and widely used lifecycle method is componentDidMount. This method is called after the component is rendered.
import React, { Component } from 'react'
export default class componentDidMountMethod extends Component {
constructor(props){
super(props)
this.state = {
name: 'This name will change in 5 sec'
}
}
componentDidMount() {
setTimeout(() => {
this.setState({name: "This is a componentDidMount Method"})
}, 5000)
}
render() {
return (
<div>
<p>{this.state.name}</p>
</div>
)
}
}
output:
This is a componentDidMount Method
The above example will print This is a componentDidMount Method after 5 sec. This proves that the method is called after the component is rendered.
This is the second phase of the React lifecycle. A component is updated when there is a change in state and props React basically has five built-in methods that are called while updating the components.
shouldComponentUpdate() is used when you want your state or props to update or not. This method returns a boolean value that specifies whether rendering should be done or not. The default value is true.
import React, { Component } from 'react'
export default class shouldComponentUpdateMethod extends Component {
constructor(props){
super(props)
this.state = {
name: 'shouldComponentUpdate Method'
}
}
shouldComponentUpdate() {
return false; //Change to true for state to update
}
componentDidMount(){
setTimeout(() => {
this.setState({name: "componentDidMount Method"})
}, 5000)
}
render() {
return (
<div>
<p>This is a {this.state.name}</p>
</div>
)
}
}
componentDidUpdate method is called after the component is updated in the DOM. This is the best place in updating the DOM in response to the change of props and state.
import React, { Component } from 'react'
export default class componentDidUpdateMethod extends Component {
constructor(props){
super(props)
this.state = {
name: 'from previous state'
}
}
componentDidMount(){
setTimeout(() => {
this.setState({name: "to current state"})
}, 5000)
}
componentDidUpdate(prevState){
if(prevState.name !== this.state.name){
document.getElementById('statechange').innerHTML = "Yes the state is changed"
}
}
render() {
return (
<div>
State was changed {this.state.name}
<p id="statechange"></p>
</div>
)
}
}
In the above example, you will notice that first I have initialized the name state inside the constructor method
and after that changed state using setState inside componentDidMount method. So basically the name
state should be changed from "shouldComponentUpdate Method" to
“componentDidMount Method” after 5 seconds but it didn’t change because of
shouldComponentUpdate set to false, If you change that true the state will be updated.
componentDidUpdate()
The componentDidUpdate method is called after the component is updated in the DOM. This is the best place in
updating the DOM in response to the change of props and state.
import React, { Component } from 'react'
export default class componentDidUpdateMethod extends Component {
constructor(props){
super(props)
this.state = {
name: 'from previous state'
}
}
componentDidMount(){
setTimeout(() => {
this.setState({name: "to current state"})
}, 5000)
}
componentDidUpdate(prevState){
if(prevState.name !== this.state.name){
document.getElementById('statechange').innerHTML = "Yes the state is changed"
}
}
render() {
return (
<div>
State was changed {this.state.name}
<p id="statechange"></p>
</div>
)
}
}
In the above example, I have set the name state to to current state So React will render the name
state from State was changed from previous state to State was changed to current state after 5
seconds. Using the conditional checking of the current state with the previous state prevState.name !==
this.state.name inside the componentDidUpdate method, we are updating the value of the id
statechange to Yes the state is changed .
componentWillUnmount()
If there are any cleanup actions like canceling API calls or clearing any caches in storage you can perform that
in the componentWillUnmount method. You cannot use setState inside this method as the component will never be
re-rendered.
import React, { Component } from 'react'
export default class componentWillUnmount extends Component {
constructor(props){
super(props)
this.state = {
show: true,
}
}
render() {
return (
<>
<p>{this.state.show ? <Child/> : null}</p>
<button onClick={() => {this.setState({show: !this.state.show})}}>Click me to toggle</button>
</>
)
}
}
export class Child extends Component{
componentWillUnmount(){
alert('This will unmount')
}
render(){
return(
<>
I am a child component
</>
)
}
}
In the above example, I have created a simple toggle button which will show our Child component if
the state is set to true.
So after clicking on the button an alert will popup displaying This will unmount The alert will
popup because the component is about to be removed from the DOM which in our case is the Child component.
In React, a list is a collection of elements rendered with a map function. Each element in the list is assigned a unique identifier known as a key. Keys are crucial for React to efficiently update and reconcile the virtual DOM when the list changes.
Let's consider a scenario where we want to render a list of items in React. We can create a component for the list and map over the items to generate the list dynamically.
List Component Example:
import React from 'react';
const ListComponent = ({ items }) => {
return (
<ul>
{items.map((item) => (
<li key={item.id}>{item.name}</li>
))}
</ul>
);
};
export default ListComponent;
key Prop:Consider a list of items with unique identifiers (IDs) and names:
const items = [
{ id: 1, name: 'Item 1' },
{ id: 2, name: 'Item 2' },
{ id: 3, name: 'Item 3' },
];
In the ListComponent example:
map function is used to iterate over each item in the items array.li element has a key prop set to the unique id of the item.Usage of ListComponent:
import React from 'react';
import ListComponent from './ListComponent';
const App = () => {
const items = [
{ id: 1, name: 'Item 1' },
{ id: 2, name: 'Item 2' },
{ id: 3, name: 'Item 3' },
];
return (
<div>
<h1>List Component Example</h1>
<ListComponent items={items} />
</div>
);
};
export default App;
Key Takeaways:
key prop when rendering lists in React.Event handling essentially allows the user to interact with a webpage and do something specific when a certain event like a click or a hover happens.
When the user interacts with the application, events are fired, for example, mouseover, key press, change event, and so on.
The actions to which JavaScript can respond are called events. Handling events with react is very similar to handling events in DOM elements.
Below are some general events that you would see in and out when dealing with React-based websites:
React event handling is similar to HTML with some changes in syntax, such as:
React uses camelCase for event names while HTML uses lowercase.
Instead of passing a string as an event handler, we pass a function in React.
Example: In HTML:
<button onclick="clickHandler()">
Clicked
</button>
In React js
<button onClick={clickHandler}>
Clicked
</button>
Also, like in HTML, we cannot return false to prevent default behavior; we need to use preventDefault to prevent the default behavior.
In HTML
<form onsubmit="console.log('clicked');
return false">
<button type="submit">Submit</button>
</form>
In React js
function Form() {
function handleClick(e) {
e.preventDefault();
console.log('Clicked');
}
return (
<form onSubmit={handleClick}>
<button type="submit">Submit</button>
</form>
);
}
Here, e is a synthetic event. React events do not work exactly the same as native events. See the SyntheticEvent reference guide to learn more.
When using React, you generally don’t need to call addEventListener to add listeners to a DOM element after it is created. Instead, just provide a listener when the element is initially rendered.
Changing state in onClick event listener:
function EventBind() {
const [steps, setSteps] = useState(0);
const clickHandler = () => {
setSteps(steps + 1);
};
return (
<>
<div>{steps}</div>
<button onClick = {clickHandler}> Click </button>
</>
);
}
export default EventBind
Let’s see some of the event attributes:
In order to work as a cross-browser application, React has created a wrapper same as the native browser in order to avoid creating multiple implementations for multiple methods for multiple browsers, creating common names for all events across browsers. Another benefit is that it increases the performance of the application as React reuses the event object.
It pools the event already done hence improving the performance.
e.preventDefault()prevents all the default behavior by the browser.
e.stopPropagation()prevents the call to the parent component whenever a child component gets called.
Note: Here ‘e’ is a synthetic event, a cross-browser object. It is made with a wrapper around the actual event of the browser.
Pure components in React are a type of component that only re-renders when its props or state change. They are also referred to as “stateless components” or “dumb components”. Pure components are a way to optimize the performance of your React application by reducing unnecessary re-renders.
import React, { PureComponent } from 'react'
export default class PureComp extends PureComponent {
constructor(){
super();
this.state={
count:0
}
}
render() {
console.log("Component is called")
return (
<div>
<h1> {this.state.count}</h1>
<button onClick={()=>this.setState({count:this.state.count+1})}>Click</button>
</div>
)
}
}
In React, a Higher-Order Component (HOC) is a function that takes a component as an input and returns a new component with additional functionality. Essentially, it's a way to reuse component logic and share it between different components.
To use a HOC, you simply pass your component as an argument to the function that defines the HOC. The function returns a new component with the added functionality.
So in this below example im going to create one counter and hover counter basically , whenever i hover over the text the counter should be updated by one.
App.js
import React from "react";
import ClickCounter from "./ClickCounter";
import HoverComp from "./HoverComp";
const App = () => {
return (
<div>
<ClickCounter />
<HoverComp />
</div>
);
};
export default App;
ClickCounter.js
import React from "react";
import UpdatedComp from "./UpdatedComp";
const ClickCounter = ({ count, incrementCount }) => {
console.log(incrementCount);
return <button onClick={incrementCount}> Count {count} Times </button>;
};
export default UpdatedComp(ClickCounter);
HoverComp.js
import React from "react";
import UpdatedComp from "./UpdatedComp";
const HoverComp = ({ count, incrementCount }) => {
console.log(incrementCount);
return <h2 onMouseOver={incrementCount}> Hovered {count} Times </h2>;
};
export default UpdatedComp(HoverComp);
UpdatedComp.js
import React, { useState } from "react";
const UpdatedComp = (OriginalComponent) => {
const NewComponent = () => {
const [count, setCount] = useState(0);
const incrementCount = () => {
setCount(count + 1);
};
return <OriginalComponent count={count} incrementCount={incrementCount} />;
};
return NewComponent;
};
export default UpdatedComp;
Output:
So after hovering over the text and click on the button the counter will update by one.
In this code, the UpdatedComp function is the higher-order component. It takes a component as its argument and
returns a new component with an added state count and a method incrementCount that
updates the count. The OriginalComponent is rendered inside the NewComponent, and the count and
incrementCount props are passed to it.
Both ClickCounter and HoverComp components are wrapped in the UpdatedComp higher-order component to enhance them
with the count state and incrementCount method. Therefore, they have access to the count and
incrementCount props, which they can use to update their state and re-render.
In summary, the higher-order component in this code is the UpdatedComp function that takes a component as an argument and returns a new component with added functionality. It is used to enhance the ClickCounter and HoverComp components with state and methods.
In React, Hooks are functions that allow developers to use state and other React features in functional components without the need for class components.
Hooks were introduced in React version 16.8 to provide a simpler and more flexible way to manage state and side effects in React components.
In class component we use different Life cycle methods but in functional components we use hooks instead.
Hooks allows to use state and other features without writing a class.
Benefits of using Hooks and Why Hooks was introduced ?
● In react class component, we split our work into different life-cycle methods like componentDidMount, componentDidUpdate and componentWillUnmount, but in hooks, we can do everything in a single hook called useEffect.
● In the class component, we have to use this keyword and also we have to bind event listeners, which increases complexity. This is prevented in react functional components.
There is 2 rules to use Hooks.
Only call Hooks at the top level:-
Do not call hooks inside loops, conditions or nexted functions. Hooks should always be used at the top level of the react functions.
Only call hooks from React functions:-
You can't call hooks from regular js functions instead you can call hooks from React functional component.
There are several types of hooks in React such as:
-> usestate hooks allows us to track state in a functional component.
-> State generally refers to data or properties that need to be tracking in an application.
-> usestate can be used to toggle between 2 values, usually true and false.
How to use it
first we have to import
import {usestate} from 'react'
then inside a function write
const[count.setCount]=usestate(0);
| |
| |
(current (Update the
state) counter's state)
Example
import React ,{useState} from "react";
function App() {
const[Count,setCount]= useState(0);
return(
<>
<h1> count:{Count}</h1>
<button onClick={()=>setCount(Count+1)}>Click</button>
</>
)
}
export default App
In this example, we declare a state variable called count using the useState hook and initialize it
to 0. We also declare a function called setCount which will be used to update the count
state variable.
MultiCounter Applicarion
import React from 'react'
import { useState } from 'react';
const Function = () => {
const[count,setCount] = useState([0,0])
const increment=(index)=>{
setCount((prevCount)=>{
const newCount = [...prevCount]
console.log(newCount);
newCount[index] += 1
return newCount
})
}
const decrement=(index)=>{
setCount((prevCount)=>{
const newCount = [...prevCount]
newCount[index] -= 1
return newCount
})
}
console.log(count)
return (
<div>
{count.map((counter,index)=>(
<div key={index}>
<h1> count:{counter}</h1>
<button onClick={()=>increment(index)}>increment</button>
<button onClick={()=>decrement(index)}>decrement</button>
</div>
))}
</div>
)
}
export default Function
-> The Effect Hook allows us to perform side effects (an action) in the function components. It does not use components lifecycle methods which are available in class components.
-> In other words, Effects Hooks are equivalent to componentDidMount(), componentDidUpdate(), and componentWillUnmount() lifecycle methods.
-> useEffect allows you to run side effects after the component has rendered, and also provides a way to clean up any side effects when the component is unmounted or updated. Here is an example of how to use useEffect:
Side effects have common features which the most web applications need to perform, such as:
-> useEffect accepts 2 arguments (callback,[dependency])
The dependency array is passed as the second argument to useEffect, and can contain one or more values. If the array is empty, the effect will only run once, when the component is mounted. If the array contains any values, the effect will re-run whenever one of those values changes.
function App() {
const[Count,setCount]= useState(0);
const [num,setNum]= useState(0);
useEffect(()=>{
alert("clicked")
})
return(
<>
<h1> count:{Count}</h1>
<button onClick={()=>setCount(Count+1)}>Click</button>
<h1> Number:{num}</h1>
<button onClick={()=>setNum(num+1)}>Click</button>
</>
)
}
export default App
Output:
Here we declare 2 states setCount and setNum. and add counter to both of them . And we
use useeffect and alert. so when one user click on the both buttons in every render one alert will appear.
Now lets use empty dependency
useEffect(()=>{
alert("clicked")
},[])
So we just add empty array dependency, now when ever the page is reload for the first time it will show alert. Then whenever we click on both buttons the alert will not popup.
useEffect(()=>{
alert("clicked")
},[num])
Here we pass num state in the dependency.Now when we click on count state button the alert will not popup but whenever we click on num state button the alert will popup everytime we click on the button and simontaniouly the increment will occure.
import React from 'react'
import { useState, useEffect } from 'react';
const Function = () => {
const[data,setData] = useState([])
//componentDidMount(runs once after the initial render)
useEffect(()=>{
console.log("component did mount")
const fetchData= async()=>{
const result = await fetch('https://jsonplaceholder.typicode.com/users')
const json = await result.json();
// console.log(json);
setData(json);
}
fetchData();
//component willunmount
return()=>{
console.log("component will unmount")
}
},[]);
//component DidUpdate (runs on every render,but can be controlled with dependancies)
useEffect(()=>{
console.log(data,"update data")
},[data])//this effect runs ehwnever 'data' chnages
console.log("render")
return (
<div>
<ul>
{data.map(item =>(
<li key={item.id}> {item.name}</li>
))}
</ul>
</div>
)
}
export default Function
The useEffect hook is crucial in React for managing side effects in functional components. A
side effect refers to anything that affects something outside the scope of the function, such as
fetching data, updating the DOM, or setting timers. The useEffect hook runs after every render by
default, but it can also be controlled to run only when specific values change, making it highly useful for
various scenarios.
Here are some unique and good examples of using the useEffect hook:
Fetching data from an external API is one of the most common use cases for useEffect. The hook helps
you trigger an API call when the component mounts, ensuring that data is loaded as soon as the component is
rendered.
import React, { useState, useEffect } from 'react';
const DataFetching = () => {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
// Simulate fetching data from an API
fetch('https://jsonplaceholder.typicode.com/posts/1')
.then((response) => response.json())
.then((json) => {
setData(json);
setLoading(false);
});
}, []); // Empty dependency array ensures this runs only once after the initial render
return (
<div>
{loading ? <p>Loading...</p> : <p>Data: {JSON.stringify(data)}</p>}
</div>
);
};
export default DataFetching;
useEffect is important here:useEffect, the API call would happen every time the component renders,
potentially causing an infinite loop.useEffect, the API call happens only once, after the initial render, which
makes it efficient and prevents unnecessary network requests.This example demonstrates how you can use useEffect to create a timer (e.g., for a countdown or a
clock) and clean up the timer when the component is unmounted.
import React, { useState, useEffect } from 'react';
const Timer = () => {
const [seconds, setSeconds] = useState(0);
useEffect(() => {
const interval = setInterval(() => {
setSeconds((prevSeconds) => prevSeconds + 1);
}, 1000);
// Cleanup function to clear the interval when the component unmounts
return () => clearInterval(interval);
}, []); // Empty dependency array ensures this runs only once
return <h1>Timer: {seconds} seconds</h1>;
};
export default Timer;
useEffect is important here:useEffect is used to set up a timer when the component is mounted.return () => clearInterval(interval)) ensures that the
timer is properly cleared when the component is unmounted, preventing memory leaks.You can use useEffect to dynamically update the document title based on a piece of state. This is
useful for improving the user experience, like showing unread messages or notifications in the tab title.
import React, { useState, useEffect } from 'react';
const TitleUpdater = () => {
const [count, setCount] = useState(0);
useEffect(() => {
document.title = `You clicked ${count} times`;
}, [count]); // Only runs when `count` changes
return (
<div>
<h1>{count} clicks</h1>
<button onClick={() => setCount(count + 1)}>Click me</button>
</div>
);
};
export default TitleUpdater;
useEffect is important here:count changes, the useEffect hook ensures that the document
title is updated.useEffect only runs when the dependency (count) changes,
preventing unnecessary updates.This example demonstrates how to track and react to window size changes. useEffect is used to add
and remove an event listener on the window object.
import React from 'react'
import { useState, useEffect } from 'react';
const WindowResize=()=>{
const[widthCount,setWidthCount] = useState(window.screen.width)
console.log(widthCount)
const updatedWidth = ()=>{
console.log(window.innerWidth);
setWidthCount(window.innerWidth)
}
useEffect(()=>{
window.addEventListener('resize',updatedWidth)
return()=>{
window.removeEventListener('resize',updatedWidth)
}
})
return(
<>
<p>The actual size of the window:</p>
<h1>{widthCount}</h1>
</>
)
}
export default WindowResize
useEffect is important here:This example shows how useEffect can be used to persist state across page reloads
by syncing it with localStorage.
import React, { useState, useEffect } from 'react';
const DarkModeToggle = () => {
const [darkMode, setDarkMode] = useState(false);
useEffect(() => {
const savedMode = localStorage.getItem('darkMode') === 'true';
setDarkMode(savedMode);
}, []); // Runs once to load the initial value from localStorage
useEffect(() => {
// Sync dark mode state with localStorage
localStorage.setItem('darkMode', darkMode);
}, [darkMode]); // Runs whenever `darkMode` changes
return (
<div style={{ background: darkMode ? '#333' : '#fff', color: darkMode ? '#fff' : '#000' }}>
<h1>{darkMode ? 'Dark Mode' : 'Light Mode'}</h1>
<button onClick={() => setDarkMode(!darkMode)}>
Toggle Dark Mode
</button>
</div>
);
};
export default DarkModeToggle;
useEffect is important here:useEffect runs only once to load the saved dark mode setting from
localStorage when the component mounts.
useEffect syncs the state with localStorage whenever
darkMode changes, ensuring that the dark mode preference is saved between sessions.
useEffect important in these examples?useEffect is designed for this purpose.useEffect can be controlled to
run only when necessary, making the app more efficient and preventing unnecessary re-renders or actions.useEffect allows you to clean up after side
effects, like removing event listeners, clearing timers, or canceling API requests. This is crucial for
preventing memory leaks or performance issues in React apps.The useRef hook in React is a powerful tool that allows you to create a reference to a DOM element. This reference can be used to read or modify properties of the DOM element, effectively allowing you to manipulate the DOM directly from your React code.
A mutable variable is a variable that can change its value or state during a program.
It returns an object with a single property, current, which initially holds the value passed as
argument (or undefined if no argument is provided). We can modify the current property without
triggering a re-render of the component. This makes it useful for managing mutable values and for accessing the
underlying DOM elements.
Example-1:
import React, { useEffect, useRef, useState } from 'react'
const UseRefHook = () => {
const[input,setInput] = useState("");
// const[count,setCount] = useState(0)
const count = useRef(0) ;
console.log(count);
useEffect(()=>{
console.log("render");
// setCount(count+1);
count.current = count.current+1
})
return (
<div>
<input type='text' value={input} onChange={(e)=>setInput(e.target.value)}/>
<h1>Render count:{count.current}</h1>
</div>
)
}
export default UseRefHook
Output:
In the example,
The component has a local state variable called inputValue that is initialized with an empty string
using useState. setInputValue is a function used to update the value of inputValue state
variable when the input field changes.
The component also has a count variable initialized with a value of 0 using the useRef hook. count
is used to keep track of the number of times the component has been rendered.
The useEffect hook is used to update the value of count variable whenever the component is rendered. The useEffect hook runs after the component has been rendered, and it updates the count variable by incrementing it by 1.
The component returns two elements: an input field and an h1 element that displays the current value of count. Whenever the input field is changed, the setInputValue function is called, which updates the inputValue state variable and causes the component to re-render. When the component is re-rendered, the useEffect hook runs and updates the value of count to reflect the new render count.
Example-2:
import React, { useEffect, useRef, useState } from 'react'
const UseRefHook = () => {
const[input,setInput] = useState("");
const count = useRef(0) ;
console.log(count);
const changeStyle=()=>{
console.log(count.current)
count.current.style.backgroundColor = "cyan";
}
return (
<div>
<input type='text' ref={count} value={input} onChange={(e)=>setInput(e.target.value)}/>
<button onClick={changeStyle}>Change Color</button>
</div>
)
}
export default UseRefHook
Example-3:
import React, { useRef } from 'react';
const VideoPlayer = () => {
const videoRef = useRef(null); // useRef to access the video element
const playVideo = () => {
videoRef.current.play(); // Play the video using the DOM reference
};
const pauseVideo = () => {
videoRef.current.pause(); // Pause the video using the DOM reference
};
return (
<div>
<video
ref={videoRef}
width="600"
controls
src="https://www.w3schools.com/html/mov_bbb.mp4"
/>
<div>
<button onClick={playVideo}>Play</button>
<button onClick={pauseVideo}>Pause</button>
</div>
</div>
);
};
export default VideoPlayer;

In simple terms, useRef can be used to store values that don't change often and are not used for rendering purposes, such as DOM elements, timers, or any other mutable value.
In software development, we’re generally obsessed with performance gains and how to make our applications perform faster to give users a better experience.
In simple terms, memoization is a process that allows us to cache the values of recursive/expensive function calls so that the next time the function is called with the same argument(s), the cached value is returned rather than having to re-compute the function.
This ensures that our applications run faster because we avoid the time it would usually take to re-execute the function by returning a value that’s already stored in memory.
React.memo() was released with React v16.6. While class components already allowed you to control re-renders with the use of PureComponent or shouldComponentUpdate, React 16.6 introduced the ability to do the same with functional components.
//Parent.js
import React, { useState } from 'react'
import DisplayTodo from './DisplayTodo';
const Parent = () => {
console.log("parent component rendered")
const [todo,setTodo] = useState([
{id:1,content:"walking"},
{id:2,content:"coding"}
]);
const[text,setText] = useState("")
const handleTodo=()=>{
let newTodo = {
id:3, content: text
};
setTodo([...todo,newTodo])
}
return (
<div>
<input type='text' value={text} onChange={(e)=>setText(e.target.value)}/>
<button onClick={handleTodo}>Add </button>
<DisplayTodo todo ={todo}/>
</div>
)
}
export default Parent
//DisplayTodo.js
import React from 'react'
import TodoItem from './TodoItem'
const DisplayTodo = React.memo(({todo}) => {
console.log("display todo rendered")
return (
<>
<ul>
{todo.map((item)=>(
<TodoItem key={item.id} item={item}/>
))}
</ul>
</>
)
})
export default DisplayTodo
//TodoItem.js
import React from 'react'
const TodoItem = React.memo(({item}) => {
console.log("Todo item rendered")
return <li>{item.content}</li>
})
export default TodoItem
In this code
React.memo is used in DisplayTodo and TodoItem to optimize performance
by preventing unnecessary re-renders if the props haven't changed.DisplayTodo to help
React efficiently update the virtual DOM.In summary, this React application allows users to add todo items through a form in the Parent
component, and the added items are displayed in a list through the DisplayTodo component, with each
item rendered by the TodoItem component. The use of React memoization helps optimize the rendering
performance of the components.
import React, { useState } from 'react';
// Child component wrapped with React.memo to prevent unnecessary re-renders const ChildComponent = React.memo(({ value }) => { console.log('Child re-rendered'); return
function ParentComponent() { const [count, setCount] = useState(0); const [otherValue, setOtherValue] = useState(0);
console.log('Parent re-rendered');
return (
Count: {count}
<button onClick={() => setCount(count + 1)}>Increment Count <p>Other Value: {otherValue}</p>
<button onClick={() => setOtherValue(otherValue + 1)}>Increment Other Value</button>
{/* Child component receives otherValue as prop */}
<ChildComponent value={otherValue} />
</div>
); }
export default ParentComponent;
useMemo is a React hook that allows you to memoize the result of a function, and recompute the result only when the dependencies of the function have changed.
In simple terms, useMemo can be used to optimize the performance of your React components by avoiding unnecessary re-renders.
Let's go over an example to clarify how useMemo works and how it prevents unnecessary
re-renders and recalculations. I'll walk you through step by step with and without useMemo.
You have a function that performs an expensive calculation, like squaring a large number. You
want to display the result in a component, but you don't want to re-calculate it unless the input changes.
Without useMemo, this expensive calculation will happen on every render, but with
useMemo, it will only happen when necessary.
useMemoimport React, { useState } from 'react';
function App() {
const [number, setNumber] = useState(0);
const [otherValue, setOtherValue] = useState(0);
// Simulate an expensive calculation
const expensiveCalculation = (num) => {
console.log('Running expensive calculation...');
for (let i = 0; i < 1000000000; i++) {} // Time-consuming task
return num * num;
};
// Calculate result every time component renders
const result = expensiveCalculation(number);
console.log("Component re-rendered");
return (
<div>
<p>Number: {number}</p>
<p>Expensive Calculation Result: {result}</p>
<button onClick={() => setNumber(number + 1)}>Increment Number</button>
<button onClick={() => setOtherValue(otherValue + 1)}>Increment Other Value</button>
</div>
);
}
export default App;
useMemo:number hasn't changed.
"Running expensive calculation..." in the console on every render.number, the expensive calculation still runs.
This is a performance issue because the calculation is expensive (i.e., takes a lot of time), but it is being recalculated on every render, even when it's not necessary.
useMemoNow let's use useMemo to avoid recalculating the expensive result unless number
changes:
import React, { useState, useMemo } from 'react';
function App() {
const [number, setNumber] = useState(0);
const [otherValue, setOtherValue] = useState(0);
// Simulate an expensive calculation
const expensiveCalculation = (num) => {
console.log('Running expensive calculation...');
for (let i = 0; i < 1000000000; i++) {} // Time-consuming task
return num * num;
};
// Use useMemo to cache the result unless `number` changes
const result = useMemo(() => expensiveCalculation(number), [number]);
console.log("Component re-rendered");
return (
<div>
<p>Number: {number}</p>
<p>Expensive Calculation Result: {result}</p>
<button onClick={() => setNumber(number + 1)}>Increment Number</button>
<button onClick={() => setOtherValue(otherValue + 1)}>Increment Other Value</button>
</div>
);
}
export default App;
useMemo:expensiveCalculation(number)) will only run when
number changes.
number changes, so useMemo
will recalculate the result.number
doesn't change, so useMemo will return the cached result and skip the expensive
calculation.useMemo:number hasn't changed.
number
changes, yet it's being recalculated unnecessarily.useMemo:number) changes.useMemo ensures that the expensive calculation is skipped
when it's not needed."Component re-rendered" and
"Running expensive calculation..." will appear in the console.
"Component re-rendered" will appear, but the expensive calculation is
skipped because the value of number hasn't changed.
useMemo, every button click triggers the expensive calculation, even when the
calculation isn't needed.useMemo, the expensive calculation only runs when number changes,
significantly improving performance.With/Without useMemo |
Calculation Behavior | Component Behavior |
|---|---|---|
Without useMemo |
Expensive calculation runs on every render | Component re-renders on state change |
With useMemo |
Expensive calculation only runs when the dependency changes (number) |
Component re-renders, but recalculations are avoided if number is unchanged |
In summary, useMemo is a React hook that can be used to memoize the result of a function and optimize the performance of your components. By avoiding unnecessary re-renders, you can create faster and more efficient React applications.
useCallback will return a memoized version of the callback that only changes if one of the dependencies has changed. This is useful when passing callbacks to optimized child components that rely on reference equality to prevent unnecessary renders.
In simple terms, useCallback can be used to optimize the performance of your React components by avoiding
unnecessary re-renders of child components.
Certainly! Let's break down the useCallback hook, how it works, and how it
differs from useMemo. I'll explain when to use it, provide an example, and show why it's
useful for performance optimization in React.
useCallback?useCallback is a React hook that returns a memoized version of a
function.useMemo and useCallback:useMemo: Memoizes the result of a computation.useCallback: Memoizes the function itself.useCallback:Imagine a parent component that passes a function as a prop to a child component. Each time the parent
re-renders, a new instance of that function is created, which could cause the child to
unnecessarily re-render. useCallback helps prevent this by ensuring the same function instance is
reused unless its dependencies change.
useCallbackHere’s an example of a parent component passing a function (handleClick) to a child component
without using useCallback.
useCallback):import React, { useState } from 'react';
import ChildComponent from './ChildComponent';
function ParentComponent() {
const [count, setCount] = useState(0);
const [otherValue, setOtherValue] = useState(0);
// Function that gets passed to the child
const handleClick = () => {
console.log('Button clicked!');
};
console.log('Parent re-rendered');
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment Count</button>
<button onClick={() => setOtherValue(otherValue + 1)}>Increment Other Value</button>
<ChildComponent handleClick={handleClick} />
</div>
);
}
export default ParentComponent;
import React from 'react';
function ChildComponent({ handleClick }) {
console.log('Child re-rendered');
return (
<div>
<button onClick={handleClick}>Click Me</button>
</div>
);
}
export default ChildComponent;
useCallback:handleClick is recreated as a new function, even though
the logic inside it doesn’t change.handleClick to the child, the child
component re-renders unnecessarily every time the parent re-renders, even though the child's
props haven't logically changed.useCallbackNow let's use useCallback to memoize the handleClick function so that the child
only re-renders when handleClick truly changes.
useCallback):import React, { useState, useCallback } from 'react';
import ChildComponent from './ChildComponent';
function ParentComponent() {
const [count, setCount] = useState(0);
const [otherValue, setOtherValue] = useState(0);
// Memoize the handleClick function using useCallback
const handleClick = useCallback(() => {
console.log('Button clicked!');
}, []); // No dependencies, so the function is memoized once
console.log('Parent re-rendered');
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment Count</button>
<button onClick={() => setOtherValue(otherValue + 1)}>Increment Other Value</button>
<ChildComponent handleClick={handleClick} />
</div>
);
}
export default ParentComponent;
useCallback:handleClick is memoized. It is created once and stored in memory.handleClick remains
the same unless its dependencies change.handleClick is the same function instance on re-renders, the
child component doesn’t re-render unless handleClick or other props change.
count or
otherValue.
useCallback:useCallback when you are passing functions as props to child components and you want to
avoid unnecessary re-renders.useCallback(() => fn, [dependencies]) memoizes a function so that it is
only re-created if its dependencies change.[]), the function is only created once and reused on every
re-render.useCallback, a new function is created on each re-render. If this function is passed to
a child as a prop, the child will think its props have changed and will also re-render.useCallback, the function remains the same instance across renders, preventing the child
from unnecessarily re-rendering.useCallback with DependenciesSometimes, the function might depend on a variable from the parent component's state. In this case, you
pass that variable as a dependency to useCallback.
const handleClick = useCallback(() => {
console.log(`Button clicked! Count is ${count}`);
}, [count]); // Now handleClick will change whenever `count` changes
handleClick function depends on count. With
useCallback, it will only be recreated when count changes. This ensures the child
component only receives a new handleClick function when it's actually different.
useCallback:With/Without useCallback |
Function Behavior | Component Behavior |
|---|---|---|
Without useCallback |
A new function is created on every render | Child re-renders unnecessarily |
With useCallback |
The function is memoized and reused unless dependencies change | Child only re-renders when necessary |
useCallback?In summary, useCallback is a React hook that can be used to memoize a function and optimize the performance of your components. By avoiding unnecessary re-creation of functions, you can create faster and more efficient React applications.
useReducer is a React hook that provides a way to manage complex state logic in functional
components. It is an alternative to useState for managing state that involves multiple sub-values
or when the next state depends on the previous one.
It does very similiar to setState, It's a different way to manage state using Redux Pattern. Instead of
updating the state directly, we dispatch actions, that go to a reducer function, and this function figure out,
how to compute the next state.
Managing Complex State Logic: useReducer is particularly useful when the state logic becomes complex, involving multiple sub-values or requiring computation to determine the next state.
State Transitions: It helps in handling more advanced state transitions by providing a function that takes the current state and an action, and returns the new state.
Local Component State: While useState is often sufficient for local component
state, useReducer can be more suitable when dealing with complex state management.
useState:
useReducer:
import React,{useReducer} from 'react'
const initialState = 0;
const reducer=(state,action)=>{
if(action.type==="increment"){
return state+1
}
if(action.type==="decrement"){
return state-1
}
if(action.type==="reset"){
return 0
}
}
const Demo = () => {
const[state,dispatch] = useReducer(reducer,initialState)
return (
<div>
<h1>{state}</h1>
<button onClick={()=>dispatch({type:"increment"})}>INC</button>
<button onClick={()=>dispatch({type:"decrement"})}>DEC</button>
<button onClick={()=>dispatch({type:"reset"})}>Reset</button>
</div>
)
}
export default Demo
import React, { useReducer } from 'react';
// Reducer function
const counterReducer = (state, action) => {
switch (action.type) {
case 'INCREMENT':
return { count: state.count + 1 };
case 'DECREMENT':
return { count: state.count - 1 };
case 'RESET':
return { count: 0 };
default:
return state;
}
};
const CounterComponent = () => {
// useReducer returns current state and dispatch function
const [state, dispatch] = useReducer(counterReducer, { count: 0 });
const handleIncrement = () => {
dispatch({ type: 'INCREMENT' });
};
const handleDecrement = () => {
dispatch({ type: 'DECREMENT' });
};
const handleReset = () => {
dispatch({ type: 'RESET' });
};
return (
<div>
<h2>Count: {state.count}</h2>
<button onClick={handleIncrement}>Increment</button>
<button onClick={handleDecrement}>Decrement</button>
<button onClick={handleReset}>Reset</button>
</div>
);
};
export default CounterComponent;
function App() {
const initial = 0;
const reducer = (state, action) => {
switch (action) {
case "add": return state + 1;
case "sub": return state - 1;
case "reset": return 0;
default: return 0;
}
}
const [value, dispatch] = useReducer(reducer, initial) return (
<div>
<h2>{value}</h2>
<button onClick={() => dispatch("add")}>Add</button>
<button onClick={() => dispatch("sub")}>subtract</button>
<button onClick={() => dispatch("reset")}>reset</button>
</div>
);
}
In this example,
The component initializes a constant initial with a value of 0. This is the initial value for the
state managed by the useReducer hook. The component also defines a reducer function, which
takes in the current state and an action object, and returns a new state based on the action.
The reducer function used in this component has a switch statement that checks the type of action passed in, and returns the updated state based on the action. In this case, there are three possible actions: "add", "sub", and "reset".
If the action is "add", the reducer returns the current state plus one. If the action is "sub", the reducer returns the current state minus one. If the action is "reset", the reducer returns the initial value of 0.
The useReducer hook is used to initialize a state variable called value with the initial value of
0, and a dispatch function that allows you to dispatch actions to the reducer. The
useReducer hook takes two arguments: the reducer function and the initial state value.
The component returns a div that contains an h2 element that displays the current
value of value, and three buttons that dispatch the corresponding actions to the reducer when
clicked.
When the buttons are clicked, the dispatch function is called with the appropriate action object,
and the useReducer hook updates the state based on the action. The h2 element is re-rendered with the updated
value of value.
In many cases, if you want to add a certain feature to your application, you can simply install a third-party library that is made to solve your problem. But if such a library or hook doesn't exist? Then it's important to learn the process of creating custom hooks to solve problems or add missing features within your own React projects.
//useCustomCounter.js
import React ,{useEffect, useState} from 'react'
const useCustomCounter = (initialValue,componentName) => {
const [counter,setCounter] = useState(initialValue)
function counterApp(){
setCounter(counter+1)
}
useEffect(()=>{
console.log(componentName+"is clicked"+counter+"times")
},[counter,componentName])
return counterApp;
}
export default useCustomCounter;
//FirstComponent.js
import React from 'react'
import useCustomCounter from './UseCustomCounter'
const FirstComponent = () => {
const clickedOne = useCustomCounter(0,"FirstComponent")
return (
<div>
<h2>This is my first component</h2>
<button onClick={clickedOne}>Click</button>
</div>
)
}
export default FirstComponent
// SecondComponent.js
import React from 'react'
import useCustomCounter from './UseCustomCounter'
const SecondComponent = () => {
const counterTwo = useCustomCounter(2,"secondComponent")
return (
<div>
<h2>This is my second component</h2>
<button onClick={counterTwo}>Click</button>
</div>
)
}
export default SecondComponent
React Router is a powerful routing library built on top of React that helps to flow your application incredibly quickly, while keeping the URL in sync with what's being displayed on the page.
When a user types a specific URL into the browser, and if this URL path matches any 'route' inside the router file, the user will be redirected to that particular route.
React Router Dom is used to build applications that have many pages or components but the page is never refreshed instead the content is dynamically fetched based on the URL
Q.What is the difference between react-router and react-router-dom ?
In React Router v4, the React Router was broken into two: react-router and react-router-dom. react-router is
the core, and
react-router-dom is the core plus the React Router elements such as
<BrowserRouter> and <NavLink>
Since react-router-dom is like a super-set of react-router, you only need to import react-router-dom.
BrowserRouter is responsible for understanding the url and then going ahead and ensuring that ui that we have or component we have is as per that particular url
Installation
npm i react-router-dom
The Routes component is used to define the routes for your application. It takes one or more Route components as its children and renders the first Route that matches the current URL. If none of the Route components match the current URL, the Routes component renders nothing.
The Route component is used to define a single route in your application. It takes two props: path and element. The path prop specifies the URL pattern that the Route should match, and the element prop specifies the component that should be rendered when the Route matches.
The path prop is used to specify the URL pattern that a Route should match. It can be a string or a regular expression that matches the desired URL pattern. For example, if you want to match the URL /about with a Route, you would set the path prop to "/about".
Link is a primary way to allow users to navigate around your application from page to another without loading The difference between link and anchor tag is that
● anchor tag when we navigate to another page there is a loading happen
● Link when we navigate to another page through link the page will not load.
How to use links in React ?
Initially we are on Home page , on click of Home we move to about page and there is a change in url(localhost:3000/about)
React Router provides several types of routers for different use cases. The most commonly used routers are:
Here lets take one simple example how to perform routing . We are taking 3 pages Home, About, Contact. And i place them in ul tag as a link so that whwnever we click on particular link it will redirect to that page.
#index.js
import React from 'react';
import ReactDOM from 'react-dom/client';
import './index.css';
import App from './App';
import { BrowserRouter } from 'react-router-dom';
const root = ReactDOM.createRoot(document.getElementById('root'));
root.render(
<React.StrictMode>
<BrowserRouter>
<App />
</BrowserRouter>
</React.StrictMode>
);
#App.js
import './App.css';
import Home from './component/Home';
import About from './component/About';
import Contact from './component/Contact';
import {Routes,Route,Link} from 'react-router-dom'
function App() {
return (
<>
<ul>
<li><Link to="/">Home</Link></li>
<li><Link to="/about">About</Link></li>
<li><Link to="/contact">Contact</Link></li>
</ul>
<Routes>
<Route path="/" element={<Home/>}/>
<Route path="/about" element={<About/>} />
<Route path="/contact" element={<Contact/>}/>
</Routes>
</>
);
}
export default App;
./component/Home.js
import React from "react"
const Home=()=>{
return (
<>
Home
</>
)
}
export default Home
./component/About.js
import React from "react"
const About=()=>{
return (
<>
About
</>
)
}
export default About
./component/Contact.js
import React from 'react'
const Contact = () => {
return (
<div>Contact</div>
)
}
export default Contact
Output:
HashRouter uses the hash portion of the URL (the part after #) to keep track of
routing. For example, the URL might look like http://example.com/#/about. Everything after
# is handled client-side and not sent to the server.
HashRouter:import React from "react";
import { HashRouter as Router, Routes, Route, Link } from "react-router-dom";
import Home from "./Home";
import About from "./About";
import Contact from "./Contact";
const App = () => {
return (
<Router>
<nav>
<ul>
<li><Link to="/">Home</Link></li>
<li><Link to="/about">About</Link></li>
<li><Link to="/contact">Contact</Link></li>
</ul>
</nav>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/contact" element={<Contact />} />
</Routes>
</Router>
);
};
export default App;
# in the URL can be less clean and not as SEO-friendly.MemoryRouter keeps the URL history in memory (it doesn’t read or write to the address bar). This is useful for non-browser environments or testing purposes, or when the app doesn’t need to interact with the browser URL.
MemoryRouter:import React from "react";
import { MemoryRouter as Router, Routes, Route, Link } from "react-router-dom";
import Home from "./Home";
import About from "./About";
import Contact from "./Contact";
const App = () => {
return (
<Router initialEntries={['/']}>
<nav>
<ul>
<li><Link to="/">Home</Link></li>
<li><Link to="/about">About</Link></li>
<li><Link to="/contact">Contact</Link></li>
</ul>
</nav>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/contact" element={<Contact />} />
</Routes>
</Router>
);
};
export default App;
StaticRouter is mainly used for server-side rendering (SSR). It doesn’t change the URL and is generally used to render the app on the server before sending HTML to the client.
StaticRouter (typically used in server-side environments):import React from "react";
import { StaticRouter as Router, Routes, Route } from "react-router-dom";
import Home from "./Home";
import About from "./About";
import Contact from "./Contact";
const App = ({ location }) => {
return (
<Router location={location}>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
<Route path="/contact" element={<Contact />} />
</Routes>
</Router>
);
};
export default App;
If you are working with React Native (for mobile apps), you would use
NativeRouter instead of BrowserRouter or HashRouter. It’s provided by
react-router-native for mobile applications.
import React from 'react';
import { NativeRouter, Routes, Route, Link } from 'react-router-native';
import { Text, View } from 'react-native';
const Home = () => <Text>Home Page</Text>;
const About = () => <Text>About Page</Text>;
const App = () => (
<NativeRouter>
<View>
<Link to="/"><Text>Home</Text></Link>
<Link to="/about"><Text>About</Text></Link>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
</View>
</NativeRouter>
);
export default App;
#. It
requires server-side support.NavLink is a component provided by React Router that is similar to Link, but it
allows you to style the link based on whether it matches the current URL. It's commonly used for navigation
menus where you want to highlight the active link.
isActive: Determines if the link is currently active (as we discussed before).
className: Dynamically sets the className of the
NavLink based on whether it is active.
style: Dynamically sets the inline style of the
NavLink based on whether it is active.
to: Specifies the target route for the link.state: Passes extra state information to the route.isActive (Automatically Passed as an Argument)isActive is automatically passed to the
className and style functions to help determine if the link is active.
Example (Recap):
<NavLink
to="/home"
style={({ isActive }) => ({ color: isActive ? "yellow" : "white" })}
>
Home
</NavLink>
classNameNavLink is
active or not. This is similar to how style works but allows you to define more complex styling
rules using external CSS.Example:
<NavLink
to="/home"
className={({ isActive }) => (isActive ? "active-link" : "inactive-link")}
>
Home
</NavLink>
In your CSS file:
.active-link {
font-weight: bold;
color: yellow;
}
.inactive-link {
color: white;
}
Here, active-link will be applied when the route is active, and inactive-link will be
applied when it's not.
styleNavLink is
active or not. We've seen this in earlier examples.Example:
<NavLink
to="/about"
style={({ isActive }) => ({
textDecoration: isActive ? "underline" : "none",
color: isActive ? "green" : "gray",
})}
>
About
</NavLink>
toto prop specifies the target route for the link. It can be a
string representing the path or an object for more complex configurations (e.g., handling query parameters,
hashes, etc.).Examples:
// Basic usage
<NavLink to="/profile">Profile</NavLink>
// Using an object with query and hash
<NavLink to={{ pathname: "/profile", search: "?name=John", hash: "#details" }}>
Profile with Query and Hash
</NavLink>
In the second example, the URL would be /profile?name=John#details.
statestate prop allows you to pass additional state data to the route
you're navigating to. This data can be accessed by the target component through the
useLocation hook.
Example:
<NavLink to="/dashboard" state={{ from: "home" }}>
Dashboard
</NavLink>
/dashboard route, you can retrieve the state
({ from: "home" }) using useLocation in the target component.import { useLocation } from 'react-router-dom';
const Dashboard = () => {
const location = useLocation();
console.log(location.state); // Output: { from: "home" }
return <div>Dashboard Page</div>;
};
NavLink Propertiesimport React from 'react';
import { NavLink } from 'react-router-dom';
import './Navbar.css'; // Assume we have some CSS for active/inactive links
const Navbar = () => {
return (
<nav>
<NavLink
to="/"
end
className={({ isActive }) => (isActive ? "active-link" : "inactive-link")}
>
Home
</NavLink>
<NavLink
to="/about"
className={({ isActive }) => (isActive ? "active-link" : "inactive-link")}
style={({ isActive }) => ({ fontWeight: isActive ? "bold" : "normal" })}
>
About
</NavLink>
<NavLink
to="/contact"
state={{ from: "navbar" }}
className={({ isActive }) => (isActive ? "active-link" : "inactive-link")}
>
Contact
</NavLink>
<NavLink
to="/profile"
replace
className={({ isActive }) => (isActive ? "active-link" : "inactive-link")}
>
Profile (Replace)
</NavLink>
</nav>
);
};
export default Navbar;
Navbar.css):.active-link {
color: yellow;
text-decoration: underline;
}
.inactive-link {
color: white;
text-decoration: none;
}
/ route because of the end
prop.style prop.{ from: "navbar" } to the
/contact route.
/profile will replace the current history
entry instead of pushing a new one.isActive: Used to conditionally style or apply classes based on whether the link is active.
end: Ensures the link is only active for exact matches.className and style: Dynamically apply CSS classes or inline styles.to: Specifies the target path, and can handle complex URLs (e.g., with query parameters or
hashes).replace: Replaces the current entry in history instead of pushing a new one.state: Passes additional state to the route, which can be accessed in the destination
component.useParams() Hook in React Router?The useParams() hook is a part of React Router that allows you to access
URL parameters in your components. URL parameters are dynamic values embedded in the URL, and
useParams() enables you to extract and use them.
For example, in a URL like /user/123, 123 is a parameter that can represent a user
ID. The useParams() hook lets you grab this dynamic value and use it within your component logic.
useParams():useParams()First, define a route in your App.js or router setup that includes route
parameters.
import { BrowserRouter as Router, Route, Routes } from 'react-router-dom';
import UserDetails from './UserDetails';
function App() {
return (
<Router>
<Routes>
{/* Dynamic route with a parameter `id` */}
<Route path="/user/:id" element={<UserDetails />} />
</Routes>
</Router>
);
}
export default App;
:id in the route /user/:id represents a dynamic URL parameter.
Whatever value is placed in the id part of the URL (e.g., /user/123) will be
accessible inside the UserDetails component.useParams() in the Component:In the component (e.g., UserDetails.js), use the useParams() hook to access the
dynamic id from the URL.
import React from 'react';
import { useParams } from 'react-router-dom';
function UserDetails() {
// Extract the dynamic part of the URL
const { id } = useParams();
return (
<div>
<h1>User Details</h1>
<p>User ID: {id}</p>
{/* You can use the `id` to fetch user details from an API, etc. */}
</div>
);
}
export default UserDetails;
useParams() returns an object where the keys correspond to the named parameters in the route
(e.g., id in this case), and the values are the actual values from the URL./user/123, the useParams() hook will return
{ id: '123' }.
id in the UserDetails component to display or fetch user-specific
data (e.g., calling an API to fetch the user with ID 123).useParams()You can have multiple dynamic parameters in the URL, such as
/category/:categoryId/product/:productId.
import { useParams } from 'react-router-dom';
function ProductDetails() {
const { categoryId, productId } = useParams();
return (
<div>
<h1>Product Details</h1>
<p>Category ID: {categoryId}</p>
<p>Product ID: {productId}</p>
{/* You can now use `categoryId` and `productId` to fetch data */}
</div>
);
}
/category/electronics/product/456, the useParams() hook will
return:
{ categoryId: 'electronics', productId: '456' }
You can have optional parameters in the URL by adding a question mark (?) in the route definition,
like /post/:postId/:commentId?. This means commentId is optional and might not be
present in the URL.
import { useParams } from 'react-router-dom';
function PostDetails() {
const { postId, commentId } = useParams();
return (
<div>
<h1>Post Details</h1>
<p>Post ID: {postId}</p>
{commentId ? <p>Comment ID: {commentId}</p> : <p>No comment selected</p>}
</div>
);
}
/post/123 will show only the post ID./post/123/456 will show both post ID and comment ID.You can use the dynamic parameters from useParams() to fetch data from an API. For example,
fetching details of a user based on the id parameter.
import React, { useEffect, useState } from 'react';
import { useParams } from 'react-router-dom';
function UserDetails() {
const { id } = useParams();
const [user, setUser] = useState(null);
useEffect(() => {
// Simulate API call
fetch(`https://api.example.com/users/${id}`)
.then((response) => response.json())
.then((data) => setUser(data))
.catch((error) => console.error('Error fetching user:', error));
}, [id]);
if (!user) {
return <div>Loading...</div>;
}
return (
<div>
<h1>User Details</h1>
<p>User ID: {id}</p>
<p>Name: {user.name}</p>
<p>Email: {user.email}</p>
</div>
);
}
export default UserDetails;
/user/123, the useParams() hook extracts the id
(123), and then the app fetches the user details for that ID.If a parameter is missing, you can handle it by checking whether useParams() returns
undefined for that parameter.
import { useParams } from 'react-router-dom';
function Page() {
const { pageId } = useParams();
if (!pageId) {
return <div>No page ID provided!</div>;
}
return <div>Showing Page ID: {pageId}</div>;
}
/page/, the component will render
"No page ID provided!", as pageId will be undefined.
In some cases, you might want to validate the URL parameters or handle cases where the parameter is invalid. For example, if you expect a numeric ID but the user enters a string.
import { useParams } from 'react-router-dom';
function UserDetails() {
const { id } = useParams();
if (isNaN(id)) {
return <div>Invalid user ID!</div>;
}
return <div>Valid User ID: {id}</div>;
}
/user/abc, the component will render
"Invalid user ID!" because id is not a valid number.
useParams() is used to extract URL parameters from dynamic routes in
React Router.
/user/:id).
/category/:categoryId/product/:productId).
This makes useParams() a powerful and flexible hook for building dynamic and data-driven pages in
your React apps.
Dynamic parameters in routing refer to a feature in React Router that allows you to define URL patterns with variable segments. This is useful when you want to create routes that can handle a wide range of inputs without having to define a separate route for each one.
// App.js
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import Home from './Home';
import User from './User';
function App() {
return (
<Router>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/users/:id" element={<User />} />
</Routes>
</Router>
);
}
export default App;
// Home.js
import { Link } from 'react-router-dom';
function Home() {
return (
<div>
<h1>Home</h1>
<ul>
<li><Link to="/users/1">User 1</Link></li>
<li><Link to="/users/2">User 2</Link></li>
<li><Link to="/users/3">User 3</Link></li>
</ul>
</div>
);
}
export default Home;
// User.js
import { useParams } from 'react-router-dom';
function User() {
const { id } = useParams();
return (
<div>
<h1>User {id}</h1>
<p>This is the page for User {id}.</p>
</div>
);
}
export default User;
In this example, we have three components:
When a user clicks on a link to a user page, React Router will match the URL to the Route for User and pass the id parameter as a prop. The User component then uses the useParams hook to extract the id parameter and render information specific to that user.
id URL parameter.import React from 'react';
import { BrowserRouter as Router, Routes, Route } from 'react-router-dom';
import UserList from './UserList';
import UserDetails from './UserDetails';
import Navbar from './Navbar';
function App() {
return (
<Router>
<Navbar />
<div style={{ padding: '20px' }}>
<Routes>
<Route path="/" element={<UserList />} />
<Route path="/user/:id" element={<UserDetails />} />
</Routes>
</div>
</Router>
);
}
export default App;
App component sets up the routes. When the path is /, it renders the
UserList component. When the path is /user/:id, it renders the
UserDetails component, where :id is the dynamic parameter.
import React from 'react';
import { Link } from 'react-router-dom';
const users = [
{ id: 1, name: 'John Doe' },
{ id: 2, name: 'Jane Smith' },
{ id: 3, name: 'Alice Johnson' },
];
function UserList() {
return (
<div>
<h2>User List</h2>
<ul>
{users.map((user) => (
<li key={user.id}>
<Link to={`/user/${user.id}`}>
{user.name}
</Link>
</li>
))}
</ul>
</div>
);
}
export default UserList;
Link component
that routes to /user/:id, where id is the user's unique ID. Clicking the
link will take the user to the UserDetails page for that specific user.import React, { useEffect, useState } from 'react';
import { useParams } from 'react-router-dom';
function UserDetails() {
const { id } = useParams(); // Get the id from the URL
const [user, setUser] = useState(null); // State to hold the user data
useEffect(() => {
// Simulate API call
fetch(`https://jsonplaceholder.typicode.com/users/${id}`) // Using a placeholder API
.then((response) => response.json())
.then((data) => setUser(data)) // Set the fetched data to user state
.catch((error) => console.error('Error fetching user:', error));
}, [id]);
if (!user) {
return <div>Loading...</div>; // Show a loading message if the data is not yet loaded
}
return (
<div>
<h1>User Details</h1>
<p><strong>User ID:</strong> {id}</p>
<p><strong>Name:</strong> {user.name}</p>
<p><strong>Email:</strong> {user.email}</p>
<p><strong>Phone:</strong> {user.phone}</p>
<p><strong>Website:</strong> {user.website}</p>
</div>
);
}
export default UserDetails;
useParams hook extracts the id from the URL.id. (In this
case, I'm using the jsonplaceholder.typicode.com API for sample data.)import React from 'react';
import { Link } from 'react-router-dom';
function Navbar() {
return (
<nav style={{ marginBottom: '20px', backgroundColor: '#f8f9fa', padding: '10px' }}>
<Link to="/" style={{ marginRight: '10px' }}>
Home
</Link>
</nav>
);
}
export default Navbar;
body {
font-family: Arial, sans-serif;
}
nav {
background-color: #333;
color: white;
padding: 10px;
}
nav a {
color: white;
text-decoration: none;
margin-right: 10px;
}
nav a:hover {
text-decoration: underline;
}
h1 {
color: #2c3e50;
}
ul {
list-style-type: none;
padding: 0;
}
li {
margin-bottom: 10px;
}
a {
color: #3498db;
text-decoration: none;
}
a:hover {
text-decoration: underline;
}
The useNavigate hook is a part of React Router and is used for programmatic navigation in a React
application. It provides a function that allows you to navigate to different pages or paths in response to user
actions, events, or other conditions in your application.
useNavigate:Handling Form Submissions:
You can use useNavigate to navigate to a different page after a form submission. For example,
redirecting to a success page after a form is successfully submitted.
Conditional Navigation:
Based on certain conditions or user interactions, you might want to navigate the user to different parts of
your application. useNavigate is handy for such scenarios.
Programmatic Redirects:
You can use useNavigate for programmatic redirects, where you want to take the user to a
different route based on certain conditions in your application.
Let's create a simple example where we have a form, and after submitting the form, we want to navigate to a success page.
Routing.js:
import React from "react";
import FunctionCompo from "./FunctionCompo";
import Home from "./Home";
import ClassCompo from "./ClassCompo";
import { Routes, Route, Link, NavLink } from "react-router-dom";
import User from "./User";
import "./App.css";
import CardOne from "./CardOne";
const Routing = () => {
return (
<>
<nav>
<NavLink
to="/"
style={({ isActive }) => ({
color: isActive ? "greenyellow" : "white",
})}
>
Home
</NavLink>
<NavLink to="/about" activeClassName="active">
About
</NavLink>
<NavLink to="/contact" activeClassName="active">
Contact
</NavLink>
</nav>
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<FunctionCompo />} />
<Route path="/contact" element={<ClassCompo />} />
<Route path="/users/:id" element={<User />} />
<Route path="/users/:id/CardOne" element={<CardOne />} />
</Routes>
</>
);
};
export default Routing;
User.js:
import { useParams ,useNavigate} from 'react-router-dom';
function User() {
const { id } = useParams();
console.log({id})
const navigate = useNavigate();
return (
<div>
<h1>User {id}</h1>
<p>This is the page for User {id}.</p>
<button onClick={()=>navigate('./CardOne')}>Click</button>
</div>
);
}
export default User;
CardOne.js:
import React from 'react'
import './App.css';
const CardOne = () => {
return (
<div>
Cardone component
</div>
)
}
export default CardOne
In this example:
useNavigate hook is used in the Home component.handleSubmit function is called, and it uses
navigate('/success') to navigate to the success page.
Link components in the navigation bar allow for manual navigation between the home and
success pages.When you run this application, you'll be able to see how useNavigate is employed to handle
navigation based on a form submission.
The useLocation hook is a part of React Router, and it provides access to the current location
object. The location object represents where the app is now, including information about the current URL, path,
search parameters, and more. By using useLocation, you can access this information within your
components.
useLocation:Location Object:
The useLocation hook returns a location object that contains information about the current URL.
The location object has several properties, including pathname, search,
hash, state, and key.
pathname: It represents the path of the URL.
search: It represents the query string parameters of the URL.
hash: It represents the URL fragment identifier.
state: It represents the state object, which can be passed during navigation.
key: A unique key for the location.
Let's create an example where we display information about the current location in a React component.
App.js:
import React from 'react';
import { BrowserRouter as Router, Route, Link } from 'react-router-dom';
import Home from './Home';
const App = () => (
<Router>
<nav>
<Link to="/">Home</Link>
</nav>
<Route path="/" element={<Home />} />
</Router>
);
export default App;
Home.js:
import React from 'react';
import { useLocation } from 'react-router-dom';
const Home = () => {
const location = useLocation();
return (
<div>
<h2>Home</h2>
<p>Current Path: {location.pathname}</p>
<p>Query Parameters: {location.search}</p>
<p>Hash: {location.hash}</p>
<p>State: {location.state ? JSON.stringify(location.state) : 'None'}</p>
<p>Location Key: {location.key}</p>
</div>
);
};
export default Home;
In this example:
useLocation hook is used in the Home component to get the current location.
Link component allows you to navigate between pages.When you navigate through the app, you'll see that the information about the current location is dynamically updated based on the URL changes. This can be useful for displaying dynamic content or handling navigation-related logic based on the current URL.
Often there will be a need to share state between different components. The common approach to share state between two components is to move the state to common parent of the two components. This approach is called as lifting state up in React.js
With the shared state, changes in state reflect in relevant components simultaneously. This is a single source of truth for shared state components.

It is the process by which you pass data from one component of the React Component tree to another by going through other components that do not need the data but only help in passing it around.
In a React component hierarchy, props can be passed down from a parent component to its child component, and then to its child's child component, and so on. When a component deep down in the hierarchy needs to access data or functionality that is only available in a higher-level component, the data or functionality must be passed down through all the intermediate components via props. This process is known as "props drilling".

Example 1: (With Props drilling) In this below example we are taking one Parent.js and we need to pass some datas from parent to ChildC. For that we need to pass data from parent to ChildA then ChildA to ChildB and then ChildB to ChildC.
// App.js
import Parent from "./woUsecontext/Parent";
const App=()=> {
return (
<div className="App">
<Parent />
</div>
);
}
export default App
// Parent.js
import React, { useState } from "react";
import ChildA from "./ChildA";
const Parent = () => {
const [fName, setfName] = useState("SP");
const [lName, setlName] = useState("Acharya");
return (
<>
<div>This is a Parent component</div>
<br />
<ChildA fName={fName} lName={lName} />
</>
)
}
export default Parent
//ChildA.js
import React from 'react'
import ChildB from './ChildB';
function ChildA({ fName, lName }) {
return (
<>
This is ChildA Component.
<br />
<ChildB fName={fName} lName={lName} />
</>
);
}
export default ChildA
// ChildB.js
import React from 'react'
import ChildC from './ChildC';
function ChildB({ fName, lName }) {
return (
<>
This is ChildB Component.
<br />
<ChildC fName={fName} lName={lName} />
</>
);
}
export default ChildB
//ChildC.js
import React from 'react'
function ChildC({ fName, lName }) {
return (
<>
This is ChildC component.
<br />
<h3> Data from Parent component is as follows:</h3>
<h4>{fName}</h4>
<h4>{lName}</h4>
</>
);
}
export default ChildC
Output:

Demonstrating the Data initialized in Parent, Needed in last component(Child C) have to passed down each level known as Prop Drilling.
Props drilling can have several drawbacks, including:
As props are passed down through multiple layers of components, it can result in the accumulation of unnecessary or irrelevant props in components that don't actually need them. This can make the code more complex and harder to maintain.
Passing down props through multiple layers of components can lead to tight coupling between components. If a parent component needs to be modified, it may require changes to be made in all the child components that rely on its props. This can make it harder to refactor or modify the code in the future.
Passing down props through multiple layers of components can affect the performance of the application. If the application has a large component tree with many nested components, it can slow down the rendering process and affect the user experience.
To overcome these drawbacks, alternative state management solutions such as context, Redux, or GraphQL can be used to manage the state and data more efficiently and avoid excessive props drilling.
The problem with Prop Drilling is that whenever data from the Parent component will be needed, it would have to come from each level, Regardless of the fact that it is not needed there and simply needed in last.
A better alternative to this is using useContext hook. The useContext hook is based on Context API and works on the mechanism of Provider and Consumer. Provider needs to wrap components inside Provider Components in which data have to be consumed. Then in those components, using the useContext hook that data needs to be consumed.
// App.js
import Parent from "./woUsecontext/Parent";
const App=()=> {
return (
<div className="App">
<Parent />
</div>
);
}
export default App
//Parent.js
import React, { useState, useContext } from "react";
let context = React.createContext(null);
function Parent() {
const [fName, setfName] = useState("SP");
const [lName, setlName] = useState("Acharya");
return (
<context.Provider value={{ fName, lName }}>
<div>This is a Parent component</div>
<br />
<ChildA />
</context.Provider>
);
}
function ChildA() {
return (
<>
This is ChildA Component.
<br />
<ChildB />
</>
);
}
function ChildB() {
return (
<>
This is ChildB Component.
<br />
<ChildC />
</>
);
}
function ChildC() {
const { fName, lName } = useContext(context);
return (
<>
This is ChildC component.
<br />
<h3> Data from Parent component is as follows:</h3>
<h4>{fName}</h4>
<h4>{lName}</h4>
</>
);
}
export default Parent;

Same output but this time instead of passing data through each level, It is directly consumed in the component required using useContext Hook.
-> Here we are taking one simple example where in dynamic context we are using some movie names , images and rating.
//MovieContext.js
import React from 'react';
const MovieContext = React.createContext();
export default MovieContext;
//MovieProvider.js
import React, { useState } from 'react';
import MovieContext from './MovieContext';
const MovieProvider = (props) => {
const [movies, setMovies] = useState([
{ name: "The Shawshank Redemption", image: "shawshank.jpg", rating: 9.3 },
{ name: "The Godfather", image: "godfather.jpg", rating: 9.2 },
{ name: "The Dark Knight", image: "darkknight.jpg", rating: 9.0 }
]);
return (
<MovieContext.Provider value={{ movies }}>
{props.children}
</MovieContext.Provider>
);
}
export default MovieProvider;
//MovieList.js
import React, { useContext } from 'react';
import MovieContext from './MovieContext';
const MovieList = () => {
const { movies } = useContext(MovieContext);
return (
<div>
{movies.map(movie => (
<div key={movie.name}>
<img src={movie.image} alt={movie.name} />
<h2>{movie.name}</h2>
<p>Rating: {movie.rating}</p>
</div>
))}
</div>
);
}
export default MovieList;
//App.js
import React from 'react';
import MovieProvider from './MovieProvider';
import MovieList from './MovieList';
const App = () => {
return (
<MovieProvider>
<MovieList />
</MovieProvider>
);
}
export default App;
Output:

In this example, we create a separate file for each component.
The MovieContext component is responsible for creating the context object using the
React.createContext() method.
The MovieProvider component defines the state variable movies and passes it down to its children
components through the context object using the MovieContext.Provider component.
The MovieList component retrieves the movies data from the context object using the
useContext() hook and maps over the array to render a list of movie items.
Finally, the App component renders the MovieProvider component as a parent of the MovieList component, so that the MovieList component can access the movies data from the context object.
//parent.js
import React, { createContext, useState } from "react";
import ChildOne from "./ChildOne";
export const context = createContext();
const Parent = () => {
const [name, setName] = useState("SP");
const [month,setMonth] = useState("January")
const monthData=(item)=>{
console.log(item)
setMonth(item)
}
return (
<div>
<context.Provider value={{name,monthData}}>
<h1>{month}</h1>
<p>This is parent component</p>
<h1>{name}</h1>
<ChildOne />
</context.Provider>
</div>
);
};
export default Parent;
//childOne.js
import React,{useContext} from 'react'
import {context} from './Parent';
const ChildOne = () => {
const{name,monthData} = useContext(context)
const month = "December";
return (
<div>
<p>This is ChildOne component</p>
<h1>{name}</h1>
<button onClick={()=>monthData(month)}>Click</button>
</div>
)
}
export default ChildOne
Axios :
Axios is a popular JavaScript library for making HTTP requests. It supports various HTTP methods, including GET, POST, PUT, and DELETE, allowing you to interact with APIs and fetch or send data. Below, I'll provide examples for each HTTP method using Axios and explain when to use each method.
Axios is a Javascript library used to make HTTP requests from node.js or XMLHttpRequests from the browser and it supports the Promise API that is native to JS ES6.
It can be used intercept HTTP requests and responses and enables client-side protection against XSRF. It also has the ability to cancel requests. EX: axios.get('url') .then((response) =>
Fetch:
HTTP (Hypertext Transfer Protocol) is a protocol that is used to transfer hypertext from client end to server end .
What are HTTP request Methods ?
| Axios | Fetch |
|---|---|
| Axios has url in request object. | Fetch has no url in request object. |
| Axios is a stand-alone third party package that can be easily installed. | Fetch is built into most modern browsers; no installation is required as such. |
| Axios enjoys built-in XSRF protection. | Fetch does not. |
| Axios uses the data property. | Fetch uses the body property. |
| Axios’ data contains the object. | Fetch’s body has to be stringified. |
| Axios request is ok when status is 200 and statusText is ‘OK’. | Fetch request is ok when response object contains the ok property. |
| Axios performs automatic transforms of JSON data. | Fetch is a two-step process when handling JSON data- first, to make the actual request; second, to call the .json() method on the response. |
| Axios allows cancelling request and request timeout. | Fetch does not. |
| Axios has the ability to intercept HTTP requests. | Fetch, by default, doesn’t provide a way to intercept requests. |
| Axios has built-in support for download progress. | Fetch does not support upload progress. |
Syntax: axios uses a simple syntax and provides a higher level of abstraction over the XMLHttpRequest object. On the other hand, fetch uses a lower-level syntax and requires more configuration to use effectively.
Error Handling: axios handles errors better than fetch. In axios, any response code that falls outside the range of 2xx will trigger an error, which can be easily handled using a catch block. In fetch, a response with a 404 or 500 status code will still resolve successfully, requiring additional checking of the response status.
Cross-Origin Requests: axios automatically includes credentials and headers for cross-origin requests, whereas with fetch you need to manually set the mode and credentials to include.
Here's an example of how to use axios to make a GET request:
import axios from 'axios';
axios.get('https://jsonplaceholder.typicode.com/todos/1')
.then(response => {
console.log(response.data);
})
.catch(error => {
console.log(error);
});
And here's an example of how to use fetch to make a GET request:
fetch('https://jsonplaceholder.typicode.com/todos/1')
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json();
})
.then(data => {
console.log(data);
})
.catch(error => {
console.log(error);
});
As you can see, the axios code is simpler and easier to read, and the error handling is more straightforward. The fetch code requires additional error checking and handling, making it slightly more complex.
The GET method is used to retrieve data from a specified resource. It should only retrieve data and should not have any other effect.
Example: Fetching a List of Users
import React, { useState, useEffect } from "react";
import axios from "axios";
const AxiosComp = () => {
const [posts, setPosts] = useState([]);
useEffect(() => {
// Use axios.get instead of client.get
axios.get('https://jsonplaceholder.typicode.com/posts?_limit=10')
.then((response) => {
setPosts(response.data);
})
.catch((error) => {
console.error('Axios Error:', error);
});
}, []);
return (
<>
<h1>Axios Comp</h1>
{/* Render your posts data here */}
{posts.map((post) => (
<div key={post.id}>
<h2>{post.title}</h2>
<p>{post.body}</p>
</div>
))}
</>
);
};
export default AxiosComp;
Use Cases:
The POST method is used to submit data to be processed to a specified resource. It is often used when uploading a file or submitting a form.
Example: Creating a New User
import React, { useState } from "react";
import axios from "axios";
const AxiosPostExample = () => {
const [newPost, setNewPost] = useState({
title: "",
body: ""
});
const handleCreatePost = () => {
// Make a POST request to create a new post
axios.post('https://jsonplaceholder.typicode.com/posts', newPost)
.then((response) => {
console.log('Axios POST Response:', response.data);
})
.catch((error) => {
console.error('Axios POST Error:', error);
});
};
return (
<>
<h1>Axios POST Example</h1>
<div>
<label>Title:</label>
<input
type="text"
value={newPost.title}
onChange={(e) => setNewPost({ ...newPost, title: e.target.value })}
/>
</div>
<div>
<label>Body:</label>
<textarea
value={newPost.body}
onChange={(e) => setNewPost({ ...newPost, body: e.target.value })}
/>
</div>
<button onClick={handleCreatePost}>Create Post</button>
</>
);
};
export default AxiosPostExample;
Use Cases:
The PUT method is used to update a resource or create a new resource if it doesn't exist. It replaces the entire resource with the new data.
Example: Updating User Information
import React, { useState, useEffect } from "react";
import axios from "axios";
const AxiosPutExample = () => {
const [post, setPost] = useState(null);
useEffect(() => {
// Fetch an initial post for demonstration purposes
axios.get('https://jsonplaceholder.typicode.com/posts/1')
.then((response) => {
setPost(response.data);
})
.catch((error) => {
console.error('Axios GET Error:', error);
});
}, []);
const handleUpdatePost = () => {
if (!post) {
console.error('No post data to update.');
return;
}
// Update the title of the post using axios.put
axios.put(`https://jsonplaceholder.typicode.com/posts/${post.id}`, {
title: 'Updated Post Title',
})
.then((response) => {
setPost(response.data);
console.log('Axios PUT Response:', response.data);
})
.catch((error) => {
console.error('Axios PUT Error:', error);
});
};
return (
<>
<h1>Axios PUT Example</h1>
{post && (
<div>
<h2>{post.title}</h2>
<p>{post.body}</p>
</div>
)}
<button onClick={handleUpdatePost}>Update Post Title</button>
</>
);
};
export default AxiosPutExample;
Use Cases:
The DELETE method is used to request that a resource be removed or deleted.
Example: Deleting a Post
import React, { useState, useEffect } from "react";
import axios from "axios";
const AxiosDeleteExample = () => {
const [posts, setPosts] = useState([]);
useEffect(() => {
// Fetch initial posts for demonstration purposes
axios.get('https://jsonplaceholder.typicode.com/posts?_limit=5')
.then((response) => {
setPosts(response.data);
})
.catch((error) => {
console.error('Axios GET Error:', error);
});
}, []);
const handleDeletePost = (postId) => {
// Make a DELETE request to delete a post
axios.delete(`https://jsonplaceholder.typicode.com/posts/${postId}`)
.then(() => {
// Update the state to remove the deleted post
setPosts(posts.filter(post => post.id !== postId));
console.log(`Post with ID ${postId} deleted`);
})
.catch((error) => {
console.error('Axios DELETE Error:', error);
});
};
return (
<>
<h1>Axios DELETE Example</h1>
{posts.map((post) => (
<div key={post.id}>
<h2>{post.title}</h2>
<button onClick={() => handleDeletePost(post.id)}>Delete Post</button>
</div>
))}
</>
);
};
export default AxiosDeleteExample;
Use Cases:
Choose the appropriate method based on the operation you want to perform, considering the characteristics of each method and the RESTful principles.
In React, a memory leak can occur when a component allocates memory and fails to release it after it's no longer needed. This can lead to an accumulation of unused memory, which can cause performance issues and even crash the application.
Here are a few scenarios in which memory leaks can occur in React:
Improper use of state and props: When a component's state or props are updated frequently, it can lead to a buildup of memory. For example, if a component has a setInterval() method that updates the state every second, the state object will keep growing, eventually leading to a memory leak.
Event listeners: When a component registers event listeners, such as mouse clicks or key presses, it can create a memory leak if it doesn't remove the listeners when the component is unmounted. This can cause the event listeners to accumulate, leading to memory issues.
Improper use of useEffect(): The useEffect() hook is used to perform side effects in functional components. If the hook is not used correctly, it can lead to memory leaks. For example, if a component sets up a timer in useEffect() and doesn't clear it when the component unmounts, the timer will continue running, causing a memory leak.
To prevent memory leaks in React, it's important to follow best practices, such as:
Use the useMemo() hook to memoize expensive calculations and prevent unnecessary re-renders.
Use the useCallback() hook to memoize event handlers and prevent unnecessary re-renders.
Use the useRef() hook to create references that persist across renders.
Use the useEffect() hook to clean up any resources, such as event listeners or timers, when the component unmounts.
By following these best practices, you can prevent memory leaks in your React applications and ensure optimal performance.
When we talk about state in our applications, it’s important to be clear about what types of state actually matter.
There are four main types of state you need to properly manage in your React apps:
Data that exists on our URLs, including the pathname and query parameters.
URL state is often missing as a category of state, but it is an important one.
In many cases, a lot of major parts of our application rely upon accessing URL state. Try to imagine building a blog without being able to fetch a post based off of its slug or id that is located in the URL!
Redux is a state management library commonly used with React applications. It helps manage the state of your application in a predictable way, making it easier to debug and maintain.
In Redux, the state of your entire application is stored in a single store. The only way to change the state is by dispatching actions. Actions describe the changes that you want to make, and reducers handle those changes based on the current state and the action dispatched.
Predictable State: Redux provides a predictable state container. The state changes in a controlled and predictable manner, making it easier to reason about your application's behavior.
Centralized State: All your application's state is stored in a single store, making it easier to manage and debug.
Debugging: With tools like Redux DevTools, you can track every state change and action, making debugging more straightforward.
Middleware: Redux allows you to use middleware to extend its functionality, like handling asynchronous operations.
Simplified Code:- Redux Toolkit provides a simplified API for creating and managing Redux stores. It also includes a number of utilities for common Redux tasks, such as creating reducers, handling asynchronous actions, and creating immutable state.
Improved Developer Experience:- Redux Toolkit comes with helpful development tools, including an integration with the Redux DevTools Extension, which makes it easier to debug and inspect the state of your application.
Performance Optimization:- Redux Toolkit includes a utility called "createSlice" that automatically generates optimized Redux reducer functions based on the initial state and action types you provide. This can help improve performance by reducing the amount of unnecessary work done by your reducers.
Context API:
Redux:
Redux Toolkit:
createSlice for defining reducers and configureStore for
creating the store.Redux:
Redux Toolkit:
createSlice.Redux Toolkit is a set of libraries and tools that make it easier to manage state in React applications using Redux.
It provides a simpler API for creating and managing Redux stores, includes helpful development tools, improves performance optimization, improves type safety, and provides a clear and consistent architecture for managing application state.
Overall, Redux Toolkit helps streamline the development process and improve the performance, maintainability, and scalability of your React applications that use Redux.
Store: The Redux store is the main, central bucket which stores all the states of an application. It should be considered and maintained as a single source of truth for the state of the application.
Action: (what to do) The only way to change the state is to emit an action, which is an object describing what happened
reducers:(How to do) Reducers, as the name suggests, take in two things: previous state and an action. Then they reduce it (read it return) to one entity: the new updated instance of state.
So reducers are basically pure JS functions which take in the previous state and an action and return the newly updated state.
I like to think of a reducer like a “coffee maker”. The coffee maker takes in coffee powder and water. It then returns a freshly brewed cup of coffee that we can enjoy. Based on this analogy reducers are functions that take in the current state (coffee powder) and actions (water) and brew a new state (fresh coffee).
Redux is a global state
You may need Redux if you don't want to do props drilling (passing props too deep).

Redux follows a unidirectional data flow. Redux has 3 major components: ‘actions’, ‘reducers’ and the ‘store’.
Here is a simple example of how to implement and what are ther step of redux.
-> Firstly Install the required packages:-
Install the redux and react-redux packages along with redux-toolkit package in your React application using npm.
npm install redux react-redux @reduxjs/toolkit
-> react Redux reducers:-
Create your reducers using the createSlice function provided by Redux Toolkit. This function
generates a reducer function for you, based on the initial state and the actions you define.
// countSlice.js
import { createSlice } from '@reduxjs/toolkit';
const counterSlice = createSlice({
name: 'counter',
initialState: 0,
reducers: {
increment: (state) => state + 1,
decrement: (state) => state - 1,
reset: () => 0,
},
});
export const { increment, decrement, reset } = counterSlice.actions;
export default counterSlice.reducer;
const countSlice = createSlice({...}): This line uses the createSlice function to define a new
slice of the store called "count". The createSlice function takes an object with several
properties:
~name: A string name for the slice.
~initialState: The initial state of the slice.
~reducers: An object with functions that define how the slice should respond to actions that are dispatched to the store. reducers: {...}: This section defines the two reducers for the "count" slice:
~ add: This reducer takes the current state and a payload argument (which is the value passed to
the action) and returns a new state with the payload value added to it.
Payload:- While action types allow you tell your reducer what action it should take, the payload is the data that your reducer will use to update the state. This lesson shows you how to pass an action payload along with your action type to update the state.
~ reset: This reducer takes the current state and sets it back to the initial state.
~ export const { add, reset } = countSlice.actions;
This line exports the add and reset action creators from the "count" slice. These action creators are functions that return action objects with a type property and a payload property (if applicable).
~ export default countSlice.reducer:- This line exports the "count" slice's reducer function, which takes the current state and an action object and returns the new state.
-> Create a Redux store:-
In your store.js file, create a Redux store using the configureStore function provided by Redux
Toolkit. This function takes an object with a reducer property and an optional middleware property.
configureStore is only accepting one parameter, which is an Object, which is called ConfigureStoreOptions.
// store.js
import { configureStore } from '@reduxjs/toolkit';
import counterReducer from './counterSlice';
const store = configureStore({
reducer: {
counter: counterReducer,
},
});
export default store;
import countReducer from './countSlice';: This line imports the "count" slice's reducer function from the countSlice.js file.
const store = configureStore({...}):-
This line uses the configureStore function to create a new Redux store. The
configureStore function takes an object with several properties:
reducer: An object with key-value pairs where the keys are the names of the slices in the store and the values are the reducer functions for those slices.
reducer: {...}: This section defines the reducers for the store. In this case, there is only one slice called
"count", so the countReducer function is associated with it.
-> This code sets up the Redux store for use in the React app:
In index.js file, import Provider from react-redux. The Provider component from the react-redux library is used to provide the Redux store to the app. The store object is imported from the ./store file.
// index.js
import React from 'react';
import ReactDOM from 'react-dom';
import App from './App';
import { Provider } from 'react-redux';
import store from './store';
ReactDOM.render(
<Provider store={store}>
<App />
</Provider>,
document.getElementById('root')
);
-> Connect Redux to React components:
Use the useSelector and useDispatch hooks provided by the react-redux package to
connect your React components to the Redux store.
// App.js
import React from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { increment, decrement, reset } from './counterSlice';
const App = () => {
const counter = useSelector((state) => state.counter);
const dispatch = useDispatch();
const handleIncrement = () => {
dispatch(increment());
};
const handleDecrement = () => {
dispatch(decrement());
};
const handleReset = () => {
dispatch(reset());
};
return (
<div>
<h2>Counter: {counter}</h2>
<button onClick={handleIncrement}>Increment</button>
<button onClick={handleDecrement}>Decrement</button>
<button onClick={handleReset}>Reset</button>
</div>
);
};
export default App;
Output:
This code defines the App component, which displays the current count and two buttons to add to the count and
reset it. The useSelector hook is used to extract the count state from the Redux store. The
useDispatch hook is used to dispatch the add and reset actions to modify the count state.
useSelector:
useDispatch:
we have 6 steps to implement the Redux Toolkit to our react project:
The most common use case for Redux Thunk is for communicating asynchronously with an external API to retrieve or save data. Redux Thunk makes it easy to dispatch actions that follow the lifecycle of a request to an external API.
Redux Thunk is middleware that allows you to return functions, rather than just actions, within Redux. This allows for delayed actions, including working with promises.
One of the main use cases for this middleware is for handling actions that might not be synchronous, for example, using axios to send a GET request.
Redux Thunk allows us to dispatch those actions asynchronously and resolve each promise that gets returned.
Suppose you have an application that needs to fetch data from an API and display it in the UI. You can use Redux-thunk to handle asynchronous actions in Redux.
First, you would define your Redux store with the redux-thunk middleware:
import { createStore, applyMiddleware } from 'redux';
import thunk from 'redux-thunk';
import rootReducer from './reducers';
const store = createStore(
rootReducer,
applyMiddleware(thunk)
);
export default store
Next, you would create an action creator that makes an API request and dispatches actions to update the Redux store:
import axios from 'axios';
export const fetchPosts = () => {
return (dispatch) => {
dispatch({ type: 'FETCH_POSTS_REQUEST' });
axios.get('https://jsonplaceholder.typicode.com/posts')
.then(response => {
const posts = response.data;
dispatch({ type: 'FETCH_POSTS_SUCCESS', payload: posts });
})
.catch(error => {
dispatch({ type: 'FETCH_POSTS_FAILURE', error });
});
};
};
In this example, fetchPosts is a thunk action creator that returns a function instead
of an object. The function takes dispatch as an argument, which allows it to dispatch multiple
actions.
When fetchPosts is called, it dispatches a FETCH_POSTS_REQUEST action to indicate
that the API request is starting. It then makes an API request using the axios library. When the request is
successful, it dispatches a FETCH_POSTS_SUCCESS action with the response data as the payload.
If the request fails, it dispatches a FETCH_POSTS_FAILURE action with the error object.
Finally, you would use this action creator in your component to fetch the data and update the Redux store:
import React, { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { fetchPosts } from './actions';
const Posts = () => {
const dispatch = useDispatch();
const posts = useSelector(state => state.posts);
const isLoading = useSelector(state => state.isLoading);
useEffect(() => {
dispatch(fetchPosts());
}, [dispatch]);
if (isLoading) {
return <div>Loading...</div>;
}
return (
<div>
{posts.map(post => (
<div key={post.id}>
<h2>{post.title}</h2>
<p>{post.body}</p>
</div>
))}
</div>
);
};
export default Posts;
In this example, the Posts component uses the useDispatch and useSelector hooks from
the react-redux library to interact with the Redux store. It dispatches the fetchPosts action when
the component mounts using the useEffect hook. It also uses the isLoading state to
show a loading indicator while the API request is in progress. Once the request is complete, it displays the
fetched data in the UI.
That's a simple example of how Redux-thunk can be used to handle asynchronous actions in Redux.
Saga middleware is a library for handling side effects in React applications using Redux. Side effects are any operations that are not pure functions, such as making API calls, accessing browser storage, or handling asynchronous code. These effects can be difficult to manage in Redux, and Saga provides a way to handle them in a declarative and testable way.
| Redux-Thunk | Redux-Saga |
|---|---|
| Less boilerplate code | More boilerplate code |
| Easy to understand as compared to redux-saga | Difficult to understand as there are multiple concepts to learn like generator functions and redux-saga effects |
| May be difficult to scale up | Easy to scale as compared to redux-thunk |
| Action creators may hold too much async logic | Action creators stay pure |
| May get difficult to test | Comparatively easy to test as all your async logic remains together |
In summary, Thunk is a simple and lightweight library that is good for handling basic asynchronous operations, while Saga is a more powerful and flexible library that can handle more complex async scenarios.
Install Required Packages
@reduxjs/toolkit and react-redux using:
npm install @reduxjs/toolkit react-redux
Create the Slice
counterSlice.js, define a slice with:increment, decrement, and reset.increment, decrement, reset) and the reducer.
Set Up the Store
store.js, use configureStore from Redux Toolkit:reducer: { slicename: counterReducer }.Build the Counter Component
CounterComponent.js, create a functional React component:useSelector to read the state. useSelector(state=>state.slicename)useDispatch to dispatch actions (increment, decrement,
reset).
Connect Redux to React
App component with <Provider> in index.js:store as a prop to the Provider.store.js: Store setup.counterSlice.js: Slice and actions.CounterComponent.js: React component.Zustand is a small, fast, and scalable bearbones state-management solution. It has a comfy API based on hooks and isn't boilerplatey or opinionated.
import { create } from 'zustand'
const useStore = create((set) => ({
bears: 0,
increasePopulation: () => set((state) => ({ bears: state.bears + 1 })),
removeAllBears: () => set({ bears: 0 }),
}))
function BearCounter() {
const bears = useStore((state) => state.bears)
return <h1>{bears} around here ...</h1>
}
Fiber is the new reconciliation engine in React 16. Its main goal is to enable incremental rendering of the virtual DOM.
RSCs allow developers to render components on the server and send them to the client as a non-interactive serialized format.
// This is a Server Component
async function ProductList() {
const products = await db.products.all(); // Direct DB access!
return (
<ul>
{products.map(p => <li>{p.name}</li>)}
</ul>
);
}
Zustand is a small, fast and scalable bearbones state-management solution using simplified flux principles. Has a comfy api based on hooks, isn't boilerplatey or opinionated.