LAST UPDATED: August 25, 2025
React Hello World
Hello Everyone!
In this tutorial, we will learn how to write a basic Hello World program in React.
// Example: Display Hello World using React
import React from "react";
import ReactDOM from "react-dom/client";
function App() {
return (
<h1>Hello World! Welcome to Tutorials!</h1>
);
}
// Rendering App component into root element
const root = ReactDOM.createRoot(document.getElementById("root"));
root.render(<App />);
Explanation:
Let's break down what we have done in the above code.
1. App Component
We created a functional component called App
. A component in React is a
JavaScript function that returns UI elements using JSX.
2. JSX
The line <h1>Hello World! Welcome to Tutorials!</h1>
is written in
JSX.
JSX looks like HTML but is actually JavaScript syntax for creating UI elements.
3. ReactDOM.createRoot()
This method tells React where to render our component in the HTML.
In this case, we target an element with id="root"
in index.html
.
4. Running the Code
- Create a new React project using Vite or Create React
App.
- Replace the default App.js
content with the above code.
- Run npm start
(CRA) or npm run dev
(Vite).
- Open http://localhost:3000 or http://localhost:5173 in
your browser.
Introduction to React
1.1 What is React?
React is a JavaScript library used for building user interfaces
(UI).
It was developed by Facebook and is now one of the most popular tools for web development.
Imagine your web page as a big house. React allows you to build this house using many small,
reusable blocks called components. For example, a button, a navbar, or a
profile card can each be a component.
React updates only the parts of the page that change (using something called the
Virtual DOM)
instead of reloading the whole page. This makes React apps fast and
efficient.
// Example: A simple React component
import React from "react";
function App() {
return <h1>Hello, React!</h1>;
}
export default App;
1.2 Features of React
React has some special features that make it powerful:
- Component-based: Break your UI into small, reusable pieces.
- Virtual DOM: Updates only the changed part, making apps faster.
- Declarative: You tell React what you want, and it handles the
how.
- JSX: Lets you write HTML inside JavaScript code.
- Unidirectional Data Flow: Data flows in one direction, so apps are
predictable.
- Cross-platform: With React Native, you can even build mobile apps!
// Example: Rendering a list of features
function Features() {
return (
<ul>
<li>Component-based</li>
<li>Virtual DOM</li>
<li>Declarative</li>
</ul>
);
}
1.3 Library or Framework?
React is a library, not a full framework.
A framework (like Angular) tells you how to build the whole app with strict rules.
A library (like React) gives you tools only for UI, and you can choose other tools as you
like.
For example, React doesn’t handle routing (navigating pages) by default.
If you need that, you install react-router
.
// Example: Adding React Router for navigation
import { BrowserRouter, Route } from "react-router-dom";
function App() {
return (
<BrowserRouter>
<Route path="/" element={<h1>Home</h1>} />
</BrowserRouter>
);
}
1.4 React & Other Frameworks
React is often compared with Angular and Vue:
- React: A library for UI, very flexible, needs extra libraries for other
tasks.
- Angular: A full framework by Google, comes with everything built-in
(but more complex).
- Vue: Easy to learn, mixes ideas from both React and Angular.
Think of React as a "toolbox" where you pick the tools you need,
while Angular is a "ready-made kit" with everything inside.
Task: Compare React and Angular: Which one is easier for beginners and why?
1.5 Installation & Setup
Before you can use React, you need some tools:
-
Install Node.js and npm
- Go to nodejs.org and download the LTS
version.
- Installing Node will also install npm
(Node Package Manager).
- You can check installation by running in terminal:
node -v
npm -v
-
Install a Code Editor
- The most popular one is VS
Code.
-
Create Your First React App
The easiest way is with Create React App:
npx create-react-app my-app
cd my-app
npm start
This will open a browser at http://localhost:3000
with your React app
running 🎉
-
Alternative Setup
- You can also use Vite (faster and modern) with:
npm create vite@latest my-app
cd my-app
npm install
npm run dev
After setup, open App.js
inside your project and replace the code with:
function App() {
return <h1>Hello React!</h1>;
}
export default App;
Task: Create a new React project, open App.js
, and change the
text to show your name.
JSX (JavaScript XML)
2.1 What is JSX?
JSX stands for JavaScript XML.
It allows you to write HTML-like syntax directly inside JavaScript.
JSX makes it easy to describe how the UI should look and is commonly used in React.
Although browsers don’t understand JSX directly, tools like Babel
convert JSX into regular JavaScript that browsers can run.
// Example: JSX inside React
const element = <h1>Hello, JSX!</h1>;
Task: Write a JSX element that displays your name inside an
<h2>
tag.
2.2 Embedding Expressions
In JSX, you can embed JavaScript expressions inside curly braces { }
.
This makes it possible to dynamically display variables, perform calculations, or even call
functions.
const name = "Raj";
const age = 21;
const element = <p>My name is {name} and I am {age} years old.</p>;
Task: Create a JSX element that shows the result of 10 + 5
inside a paragraph.
2.3 JSX vs HTML Differences
JSX looks like HTML, but there are some differences:
- class in HTML → className in JSX
- for in HTML → htmlFor in JSX
- All tags must be closed (e.g.,
<br />
instead of
<br>
)
- JSX can only return one root element
// Example
const element = <div className="container">
<label htmlFor="inputName">Name:</label>
<input id="inputName" />
</div>;
Task: Fix this invalid JSX:
<h1>Hello</h1><p>World</p>
.
2.4 Attributes in JSX
In JSX, attributes look like HTML but follow camelCase for multi-word
names.
// Example with attributes
const image = <img src="profile.jpg" alt="Profile" width="200" />;
Task: Create a JSX element for a link with
href="https://reactjs.org"
and text "Learn React".
2.5 JSX with Components
JSX is usually written inside components.
A component is a function that returns JSX.
// Example: Component with JSX
function Welcome() {
return <h1>Welcome to React!</h1>;
}
Task: Create a component called Greeting
that displays "Hello,
User!".
2.6 Conditional Rendering in JSX
You can use JavaScript conditions (like if
, ternary operator
)
inside JSX.
const isLoggedIn = true;
const message = <h1>{isLoggedIn ? "Welcome Back!" : "Please Sign In"}</h1>;
Task: Write JSX that shows "Adult" if age ≥ 18, otherwise "Minor".
2.7 Lists & Keys in JSX
You can display lists using the map()
function.
Each item should have a unique key
for React to track changes.
const hobbies = ["Reading", "Gaming", "Traveling"];
const list = (
<ul>
{hobbies.map((hobby, index) => (
<li key={index}>{hobby}</li>
))}
</ul>
);
Task: Create a list of your 3 favorite foods using JSX.
2.8 JSX and Styling
You can style JSX elements using style
(with an object) or by adding CSS
classes.
// Inline style
const element = <h1 style={{ color: "blue", fontSize: "24px" }}>Styled Text</h1>;
// With CSS class
const element = <p className="highlight">Hello CSS</p>;
Task: Create a red-colored heading using inline styles in JSX.
2.9 JSX Best Practices
- Always close tags (e.g.,
<img />
).
- Keep components small and focused.
- Use
className
instead of class
.
- Wrap multiple elements inside one parent (or use
<></>
fragment).
- Use keys when rendering lists.
React Components
Components are the building blocks of React applications.
A component is a reusable piece of code that defines how a part of the UI should look and
behave.
Components can be simple (just displaying text) or complex (handling state, logic, and
interactions).
3.1 Functional Components
Functional components are simple JavaScript functions that return JSX.
They are the most common type of components in modern React.
// Example Functional Component
function Welcome() {
return <h1>Hello, Functional Component!</h1>;
}
Task: Create a functional component called Greeting
that
displays "Welcome, User!".
3.2 Class Components
Class components are ES6 classes that extend React.Component
.
They can hold state and use lifecycle methods (before React 16.8 hooks were introduced).
// Example Class Component
import React, { Component } from "react";
class Welcome extends Component {
render() {
return <h1>Hello from Class Component!</h1>;
}
}
Task: Write a class component that displays your favorite hobby.
3.3 Pure Components
A Pure Component automatically prevents re-rendering if props and state don’t change.
This improves performance by avoiding unnecessary updates.
import React, { PureComponent } from "react";
class Greeting extends PureComponent {
render() {
return <h2>Hello, {this.props.name}</h2>;
}
}
3.4 Higher Order Components (HOC)
A Higher Order Component (HOC) is a function that takes a component as input and returns a
new component with additional features.
It is mainly used for reusing logic across multiple components.
// Example HOC
function withGreeting(WrappedComponent) {
return function(props) {
return (
<div>
<p>Hello from HOC!</p>
<WrappedComponent {...props} />
</div>
);
};
}
3.5 Stateless Components
Stateless components don’t manage their own state.
They only receive data via props
and render UI based on it.
function DisplayName(props) {
return <p>My name is {props.name}</p>;
}
3.6 Stateful Components
Stateful components manage their own state
.
They can update and re-render based on user interaction or logic.
import React, { useState } from "react";
function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>+</button>
</div>
);
}
3.7 Controlled Components
In controlled components, form inputs are controlled by React state.
The value of the input field is determined by the component’s state.
function ControlledInput() {
const [text, setText] = useState("");
return (
<input value={text} onChange={(e) => setText(e.target.value)} />
);
}
3.8 Uncontrolled Components
In uncontrolled components, form inputs store their own state internally, and you access
them using refs
.
import { useRef } from "react";
function UncontrolledInput() {
const inputRef = useRef(null);
function handleClick() {
alert(inputRef.current.value);
}
return (
<div>
<input ref={inputRef} />
<button onClick={handleClick}>Show Value</button>
</div>
);
}
3.9 Presentational Components
Presentational components are mainly for displaying UI.
They don’t manage logic or state, only render what is passed via props.
function ProfileCard(props) {
return (
<div>
<h2>{props.name}</h2>
<p>{props.bio}</p>
</div>
);
}
3.10 Container Components
Container components handle data and pass it to presentational components.
They separate logic from UI.
function ProfileContainer() {
const user = { name: "Rajesh", bio: "React Developer" };
return <ProfileCard name={user.name} bio={user.bio} />;
}
3.11 Render Props Components
A render props component is a technique for sharing code between components by using a
function as a prop.
function DataProvider(props) {
const data = "Hello from DataProvider!";
return props.render(data);
}
// Usage
<DataProvider render={(data) => <p>{data}</p>} />
Props & State in React
In React, Props and State are two important concepts for
managing data.
- Props (short for properties) are used to pass data from parent to child
components.
- State is used to manage data within a component that can change over
time.
4.1 Props Overview
Props allow components to receive data from their parent.
They are read-only and cannot be modified by the child component.
// Example: Passing props
function Welcome(props) {
return <h1>Hello, {props.name}!</h1>;
}
// Usage
<Welcome name="Rajesh" />
Task: Create a component Greeting
that receives your name via
props and displays it.
4.2 Default Props
Default props are used to set default values for props if none are provided by the parent
component.
function Welcome(props) {
return <h1>Hello, {props.name}!</h1>;
}
Welcome.defaultProps = {
name: "Guest"
};
// Usage
<Welcome /> // Output: Hello, Guest!
Task: Add default props to a Profile
component for name and
age.
4.3 Props Validation
Props validation ensures that components receive the correct type of data using
prop-types
.
import PropTypes from "prop-types";
function User(props) {
return <p>Age: {props.age}</p>;
}
User.propTypes = {
age: PropTypes.number.isRequired
};
Task: Create a User
component that validates props for name
(string) and age (number).
4.4 Props vs State
- Props: Passed from parent, read-only, used to configure a component.
- State: Managed within the component, can be updated, used for dynamic
behavior.
function Counter(props) {
const [count, setCount] = React.useState(props.start);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
// Usage
<Counter start={5} />
4.5 Props Drilling
Props drilling happens when props are passed down through multiple layers of components.
It can make code harder to manage; solutions include Context API
or
Redux
.
function Child({ name }) {
return <p>Hello, {name}</p>;
}
function Parent({ name }) {
return <Child name={name} />;
}
function App() {
return <Parent name="Rajesh" />;
}
4.6 State Overview
State is used to store data that can change during the lifecycle of a component.
Updating state re-renders the component automatically.
4.7 Setting State
You can set state when declaring it for the first time, usually using useState
(for functional components).
const [message, setMessage] = React.useState("Hello");
4.8 Updating State
State is updated using the setter function returned by useState
.
Updating state re-renders the component with new values.
function Message() {
const [text, setText] = React.useState("Hi");
return (
<div>
<p>{text}</p>
<button onClick={() => setText("Hello World!")} >Change</button>
</div>
);
}
4.9 State in Class Components
In class components, state is initialized in the constructor and updated with
this.setState()
.
class Counter extends React.Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}
increment = () => {
this.setState({ count: this.state.count + 1 });
};
render() {
return (
<div>
<p>Count: {this.state.count}</p>
<button onClick={this.increment}>+</button>
</div>
);
}
}
4.10 State with Hooks (useState)
The useState
hook allows functional components to use state.
It returns an array with the current state and a function to update it.
function Counter() {
const [count, setCount] = React.useState(0);
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
Task: Build a counter using useState
that increases and
decreases the count.
Condi. Rendering & Mapping
In React, we often need to decide what to render based on certain
conditions.
This is called conditional rendering.
Similarly, when displaying lists of data, we use the map()
function.
Let’s go through all the techniques step by step.
5.1 if/else Rendering
The most basic way is to use if/else
statements to decide which component or
element to render.
function Greeting(props) {
if (props.isLoggedIn) {
return <h1>Welcome back!</h1>;
} else {
return <h1>Please log in.</h1>;
}
}
Task: Create a component that shows "Admin Dashboard" if
isAdmin
is true, otherwise "User Dashboard".
5.2 Ternary Operator Rendering
A shorthand way is using the ? :
ternary operator.
It is often used inside JSX.
function Greeting(props) {
return (
<h1>{props.isLoggedIn ? "Welcome Back!" : "Please Log In"}</h1>
);
}
Task: Show "Online" if status
is true, otherwise "Offline".
5.3 Logical && Rendering
The &&
operator is useful when you want to render something only if a condition
is true.
If the condition is false, nothing will be displayed.
function Messages(props) {
return (
<div>
{props.unread > 0 && <p>You have {props.unread} new messages.</p>}
</div>
);
}
Task: Display "Discount Available!" only if hasDiscount
is
true.
5.4 Switch Case Rendering
Sometimes multiple conditions need different UI.
In such cases, switch
statements can be used.
function StatusMessage({ status }) {
switch (status) {
case "loading":
return <p>Loading...</p>;
case "success":
return <p>Data loaded successfully!</p>;
case "error":
return <p>Error loading data.</p>;
default:
return <p>Unknown status.</p>;
}
}
Task: Create a Weather
component that shows messages based on
"sunny", "rainy", or "cloudy".
5.5 Rendering Lists with map()
When rendering multiple elements (like a list), we use JavaScript’s map()
function in JSX.
function TodoList(props) {
return (
<ul>
{props.items.map(item => (
<li key={item.id}>{item.text}</li>
))}
</ul>
);
}
Task: Create a list of your 3 favorite fruits using map()
.
5.6 Key Prop in Mapping
When rendering lists, React needs a unique key
prop for each element.
This helps React optimize re-rendering.
const numbers = [1, 2, 3, 4];
function NumberList() {
return (
<ul>
{numbers.map(num => (
<li key={num}>{num}</li>
))}
</ul>
);
}
Task: Render a list of user names with unique keys.
5.7 Nested Conditional Rendering
Sometimes you may need to combine multiple conditional rendering techniques.
Example: showing different UI for multiple roles and login status.
function Dashboard({ isLoggedIn, role }) {
if (!isLoggedIn) {
return <p>Please log in.</p>;
}
return role === "admin" ? (
<h1>Welcome, Admin!</h1>
) : role === "user" ? (
<h1>Welcome, User!</h1>
) : (
<h1>Welcome, Guest!</h1>
);
}
Task: Build a component that shows different messages for "Student",
"Teacher", and "Guest" roles depending on login status.
React Hooks
Hooks are special functions in React that let you "hook into" React features such as
state, lifecycle methods, and context without writing class components.
They make React code more readable, reusable, and concise.
Below we’ll explore the most important hooks — their **purpose, syntax, and usage**.
6.1 useState
Purpose: Used to add state (data that changes over time) inside functional
components.
It returns an array → [currentValue, updaterFunction]
.
Syntax:
const [state, setState] = useState(initialValue);
import React, { useState } from "react";
function Counter() {
const [count, setCount] = useState(0); // state variable with initial value 0
return (
<div>
<p>Count: {count}</p>
<button onClick={() => setCount(count + 1)}>Increment</button>
</div>
);
}
Task: Build a counter with Increment and Decrement buttons using
useState
.
6.2 useEffect
Purpose: Handles side effects (fetching data, setting timers, adding event
listeners).
Runs after the component renders.
Dependency array decides when it runs.
Syntax:
useEffect(() => {
// effect code
return () => {
// optional cleanup code
};
}, [dependencies]);
📌 Variations of useEffect
1. Run on every render (no dependency array)
useEffect(() => {
console.log("Effect runs after every render!");
});
✅ Runs after every render (initial + updates).
2. Run only once (empty dependency array)
useEffect(() => {
console.log("Effect runs only on mount!");
fetch("https://jsonplaceholder.typicode.com/posts/1")
.then(res => res.json())
.then(data => console.log(data));
}, []);
✅ Runs only once after initial render (like componentDidMount
).
3. Run when specific dependencies change
const [count, setCount] = useState(0);
useEffect(() => {
console.log("Runs only when count changes:", count);
}, [count]);
✅ Runs only when the value inside dependency array changes.
4. With Cleanup Function
useEffect(() => {
const interval = setInterval(() => {
console.log("Interval running...");
}, 1000);
// Cleanup before unmount or re-run
return () => {
clearInterval(interval);
console.log("Interval cleared!");
};
}, []);
✅ Useful for cleaning up subscriptions, timers, or event listeners.
📌 Example: Timer with Cleanup
import React, { useState, useEffect } from "react";
function Timer() {
const [seconds, setSeconds] = useState(0);
useEffect(() => {
const interval = setInterval(() => {
setSeconds(s => s + 1);
}, 1000);
return () => clearInterval(interval); // cleanup when unmounted
}, []);
return <p>Seconds: {seconds}</p>;
}
Task: Use useEffect
to Check User Status.
6.3 useContext
Purpose: Lets you access values from React’s Context API without passing
props through every level.
Great for themes, auth state, or global data.
Syntax:
const value = useContext(MyContext);
import React, { useContext, createContext } from "react";
const ThemeContext = createContext("light");
function ThemedButton() {
const theme = useContext(ThemeContext); // consume context
return <button>Current theme: {theme}</button>;
}
function App() {
return (
<ThemeContext.Provider value="dark">
<ThemedButton />
</ThemeContext.Provider>
);
}
Task: Create a Context for "User" and display the user name in a child
component.
6.4 useReducer
Purpose: Alternative to useState
when you have complex logic.
Works with a reducer function like Redux (state, action
).
Syntax:
const [state, dispatch] = useReducer(reducerFn, initialState);
import React, { useReducer } from "react";
function reducer(state, action) {
switch (action.type) {
case "increment":
return { count: state.count + 1 };
case "decrement":
return { count: state.count - 1 };
default:
return state;
}
}
function Counter() {
const [state, dispatch] = useReducer(reducer, { count: 0 });
return (
<div>
<p>Count: {state.count}</p>
<button onClick={() => dispatch({ type: "increment" })}>+</button>
<button onClick={() => dispatch({ type: "decrement" })}>-</button>
</div>
);
}
Task: Implement a todo list reducer with add/remove actions.
6.5 useLayoutEffect
Purpose: Like useEffect
, but runs synchronously
before the screen is painted.
Useful for DOM measurements and animations.
Syntax:
useLayoutEffect(() => {
// effect logic
return () => { /* cleanup */ };
}, [dependencies]);
import React, { useLayoutEffect, useRef } from "react";
function Box() {
const boxRef = useRef(null);
useLayoutEffect(() => {
console.log("Box width:", boxRef.current.offsetWidth);
}, []);
return <div ref={boxRef} style={{ width: "200px", height: "100px", background: "lightblue" }} />;
}
6.6 useRef
Purpose: Holds a mutable value that does not cause re-renders when changed.
Commonly used to reference DOM nodes or store values between renders.
Syntax:
const refContainer = useRef(initialValue);
import React, { useRef } from "react";
function FocusInput() {
const inputRef = useRef(null);
const focusInput = () => {
inputRef.current.focus(); // access DOM node
};
return (
<div>
<input ref={inputRef} type="text" />
<button onClick={focusInput}>Focus Input</button>
</div>
);
}
Task: Use useRef
to create a stopwatch that saves the timer ID.
6.7 useMemo
Purpose: Optimizes performance by memoizing expensive calculations.
Only recalculates when dependencies change.
Syntax:
const memoizedValue = useMemo(() => computeFn(), [dependencies]);
import React, { useState, useMemo } from "react";
function ExpensiveCalculation({ num }) {
const calculation = useMemo(() => {
console.log("Calculating...");
return num * 2;
}, [num]);
return <p>Result: {calculation}</p>;
}
Task: Build a component that squares a number using useMemo
and
observe when recalculation happens.
6.8 useCallback
Purpose: Returns a memoized version of a function.
Prevents unnecessary re-renders of child components when functions are passed as props.
Syntax:
const memoizedFn = useCallback(() => { ... }, [dependencies]);
import React, { useState, useCallback } from "react";
function Button({ onClick, children }) {
console.log("Button rendered:", children);
return <button onClick={onClick}>{children}</button>;
}
function App() {
const [count, setCount] = useState(0);
const increment = useCallback(() => setCount(c => c + 1), []); // memoized
return (
<div>
<p>Count: {count}</p>
<Button onClick={increment}>Increment</Button>
</div>
);
}
Task: Pass a memoized callback to a child component and see the difference.
6.9 Custom Hooks
Purpose: Lets you extract and reuse stateful logic across components.
They are plain functions that start with use
.
Syntax:
function useCustomHook() { /* logic here */ return value; }
import { useState, useEffect } from "react";
function useWindowWidth() {
const [width, setWidth] = useState(window.innerWidth);
useEffect(() => {
const handleResize = () => setWidth(window.innerWidth);
window.addEventListener("resize", handleResize);
return () => window.removeEventListener("resize", handleResize);
}, []);
return width;
}
function App() {
const width = useWindowWidth();
return <p>Window width: {width}px</p>;
}
Task: Write a custom hook useOnlineStatus
that tracks if the
user is online/offline.
React Router DOM
React Router DOM is the standard routing library for React applications.
It allows you to create single-page applications (SPA) with multiple views,
enabling navigation without refreshing the page.
7.1 Introduction to React Router
React Router helps manage navigation between different components in a React app.
Instead of reloading pages, it renders components based on the current URL.
npm install react-router-dom
Task: Install react-router-dom
in your project.
7.2 BrowserRouter & HashRouter
These are two types of routers:
- BrowserRouter
: Uses HTML5 history API (clean URLs).
- HashRouter
: Uses #
in URLs (useful for static hosting).
import { BrowserRouter, Routes, Route } from "react-router-dom";
function App() {
return (
<BrowserRouter>
<Routes>
<Route path="/" element={<Home />} />
</Routes>
</BrowserRouter>
);
}
7.3 Routes and Route
Routes
is a container for all route definitions.
Route
defines the mapping between a path and a component.
import { Routes, Route } from "react-router-dom";
function App() {
return (
<Routes>
<Route path="/" element={<Home />} />
<Route path="/about" element={<About />} />
</Routes>
);
}
Task: Add routes for /home
and /contact
.
7.4 Link and NavLink
Link
is used for navigation without reloading the page.
NavLink
is similar but adds active styles to the current link.
import { Link, NavLink } from "react-router-dom";
function Navbar() {
return (
<nav>
<Link to="/">Home</Link>
<NavLink to="/about" style={({ isActive }) => ({ color: isActive ? "red" : "black" })}>
About
</NavLink>
</nav>
);
}
7.5 Navigate / Redirect
The Navigate
component is used to redirect users programmatically.
import { Navigate } from "react-router-dom";
function Profile({ isLoggedIn }) {
return isLoggedIn ? <h1>Welcome User</h1> : <Navigate to="/login" />;
}
7.6 useNavigate Hook
The useNavigate
hook lets you navigate programmatically inside functions.
import { useNavigate } from "react-router-dom";
function Home() {
const navigate = useNavigate();
return <button onClick={() => navigate("/about")}>Go to About</button>;
}
7.7 useParams Hook
useParams
lets you access URL parameters.
import { useParams } from "react-router-dom";
function UserProfile() {
const { id } = useParams();
return <h2>User ID: {id}</h2>;
}
7.8 useLocation Hook
useLocation
gives information about the current URL (pathname, search, state).
import { useLocation } from "react-router-dom";
function ShowLocation() {
const location = useLocation();
return <pre>{JSON.stringify(location, null, 2)}</pre>;
}
7.9 Outlet for Nested Routes
Outlet
is used to render child routes inside a parent layout.
import { Outlet, Link } from "react-router-dom";
function Dashboard() {
return (
<div>
<nav>
<Link to="profile">Profile</Link>
<Link to="settings">Settings</Link>
</nav>
<Outlet /> {/* Child routes will render here */}
</div>
);
}
7.10 Protected Routes
Protected routes restrict access based on authentication.
import { Navigate } from "react-router-dom";
function ProtectedRoute({ children, isAuthenticated }) {
return isAuthenticated ? children : <Navigate to="/login" />;
}
Task: Create a protected dashboard route accessible only if logged in.
React Fragments
In React, Fragments allow you to group multiple elements without adding an
extra
DOM node (like a <div>
).
This is very useful when returning multiple components from a React component’s render
method.
8.1 Introduction to Fragments
Normally in React, when you return multiple elements, they need to be wrapped inside a
parent element.
Fragments help avoid unnecessary HTML wrappers and keep the DOM clean.
function Example() {
return (
<React.Fragment>
<h1>Hello</h1>
<p>This is a paragraph.</p>
</React.Fragment>
);
}
Task: Create a component that displays a heading and a list of items using
Fragments.
8.2 <React.Fragment> Syntax
The standard way of using fragments is by writing
<React.Fragment></React.Fragment>
.
This ensures no extra <div>
is added in the DOM.
function App() {
return (
<React.Fragment>
<h2>Welcome</h2>
<p>This content is inside a fragment.</p>
</React.Fragment>
);
}
8.3 Short Syntax <> </>
Instead of writing <React.Fragment>
, React also supports a shorthand
syntax:
<> </>
.
This is cleaner and commonly used, but it doesn’t support keys or attributes.
function App() {
return (
<>
<h2>Short Syntax</h2>
<p>This uses <> and </>.</p>
</>
);
}
Task: Rewrite the previous fragment example using short syntax.
8.4 Keyed Fragments
When rendering lists, sometimes you need to provide a key
.
Short syntax <></>
doesn’t allow keys, so you must use
<React.Fragment key="...">
.
const items = ["Apple", "Banana", "Mango"];
function ItemList() {
return items.map((item, index) => (
<React.Fragment key={index}>
<h4>Item {index + 1}</h4>
<p>{item}</p>
</React.Fragment>
));
}
Task: Display a list of students with names and grades using keyed
fragments.
8.5 Difference Between Div & Fragment
Using <div>
introduces extra DOM nodes, which may cause unwanted styling
or nesting.
<React.Fragment>
avoids this by grouping without rendering extra nodes.
// Using Div (adds extra div in DOM)
function DivWrapper() {
return (
<div>
<h1>Title</h1>
<p>Paragraph</p>
</div>
);
}
// Using Fragment (no extra div in DOM)
function FragmentWrapper() {
return (
<>
<h1>Title</h1>
<p>Paragraph</p>
</>
);
}
8.6 Use Cases of Fragments
- Returning multiple elements from a component without extra nodes.
- Rendering lists of elements without unnecessary wrappers.
- Maintaining cleaner DOM structure for CSS/HTML frameworks.
Task: Build a card component that uses fragments to wrap title, description,
and footer.
8.7 Limitations of Fragments
- Shorthand syntax
<></>
cannot accept keys or attributes.
- Cannot directly apply props like
className
or id
to fragments.
Mini Project: Profile Card
Create a profile card component where the header, body, and footer are wrapped in a fragment
instead of a div.
function ProfileCard() {
return (
<>
<h2>John Doe</h2>
<p>Software Developer</p>
<footer>Contact: john@example.com</footer>
</>
);
}
Web Storage in JavaScript
The Web Storage API provides a way to store data in the browser.
It offers two mechanisms: localStorage
and sessionStorage
.
Unlike cookies, storage data is not sent to the server on every request, making it faster
and more efficient.
9.1 Introduction to Web Storage API
Web Storage allows web applications to store key-value pairs in the browser.
The data is stored as strings and can persist even after refreshing the page.
- localStorage: Data persists even after the browser is closed.
- sessionStorage: Data persists only until the browser tab is closed.
9.2 Difference: LocalStorage vs SessionStorage
Feature |
localStorage |
sessionStorage |
Lifetime |
Persists until manually cleared |
Cleared when tab is closed |
Storage Size |
~5-10 MB |
~5 MB |
Scope |
Available across tabs and windows |
Restricted to the same tab |
9.3 Storing Data
You can store data using setItem(key, value)
.
Both key and value must be strings.
localStorage.setItem("username", "JohnDoe");
sessionStorage.setItem("theme", "dark");
Task: Store your favorite color in localStorage
and theme
preference in sessionStorage
.
9.4 Retrieving Data
Use getItem(key)
to retrieve stored values.
let user = localStorage.getItem("username");
let theme = sessionStorage.getItem("theme");
console.log(user); // "JohnDoe"
console.log(theme); // "dark"
9.5 Removing Data
You can remove specific data using removeItem(key)
, or clear all data using
clear()
.
localStorage.removeItem("username");
sessionStorage.clear();
9.6 Storing JSON Objects
Since storage only supports strings, objects must be converted to JSON using
JSON.stringify()
before storing,
and parsed back using JSON.parse()
when retrieving.
const user = {name: "Alice", age: 25};
localStorage.setItem("user", JSON.stringify(user));
let storedUser = JSON.parse(localStorage.getItem("user"));
console.log(storedUser.name); // "Alice"
9.7 Use Cases
- Saving user preferences (dark mode, language).
- Storing authentication tokens temporarily.
- Remembering shopping cart items in e-commerce websites.
- Saving form data temporarily.
9.8 Limitations
- Data is stored as strings only.
- Storage size is limited (~5MB).
- Not suitable for sensitive data (accessible via JavaScript).
- No automatic expiration like cookies.
Mini Project: Todo List with localStorage
Create a simple Todo List where tasks are stored in localStorage
so they
persist even after refreshing the page.
const tasks = JSON.parse(localStorage.getItem("tasks")) || [];
function addTask(task) {
tasks.push(task);
localStorage.setItem("tasks", JSON.stringify(tasks));
}
addTask("Learn Storage API");
console.log(JSON.parse(localStorage.getItem("tasks")));
Data Fetching in JavaScript
Data fetching is the process of requesting and retrieving data from a server or an API.
JavaScript provides multiple ways to fetch data such as the Fetch API
and
third-party libraries like Axios
.
Understanding data fetching is essential for building interactive and dynamic web
applications.
10.1 Introduction to Data Fetching
Data fetching allows us to communicate with servers to get or send data.
For example, retrieving a list of users, submitting a form, updating records, or deleting
items.
The most common data format is JSON
(JavaScript Object Notation).
10.2 Using Fetch API
The fetch()
function is a modern, built-in JavaScript API for making network
requests.
fetch("https://jsonplaceholder.typicode.com/posts")
.then(response => response.json())
.then(data => console.log(data))
.catch(error => console.error("Error:", error));
Task: Use fetch()
to get a list of users and log them to the
console.
10.3 Using Axios
Axios
is a popular third-party library that simplifies HTTP requests.
It automatically handles JSON data and works in both browsers and Node.js.
axios.get("https://jsonplaceholder.typicode.com/posts")
.then(response => console.log(response.data))
.catch(error => console.error("Error:", error));
Task: Install Axios using npm install axios
and fetch posts
from an API.
10.4 Handling JSON Response
Most APIs return data in JSON format.
With fetch()
, you need to call response.json()
, while Axios
automatically parses JSON.
// Fetch API
fetch("https://jsonplaceholder.typicode.com/users")
.then(response => response.json())
.then(users => console.log(users));
// Axios
axios.get("https://jsonplaceholder.typicode.com/users")
.then(res => console.log(res.data));
10.5 Error Handling
Errors may occur due to invalid URLs, network issues, or server problems.
Use catch()
with Promises or try...catch
with async/await.
fetch("https://wrong-url.com")
.then(response => {
if (!response.ok) throw new Error("Network response was not ok");
return response.json();
})
.catch(error => console.error("Fetch Error:", error));
10.6 Loading States
While fetching data, it’s important to show users that something is loading.
In React, you can use state to track the loading process.
let loading = true;
fetch("https://jsonplaceholder.typicode.com/posts")
.then(res => res.json())
.then(data => {
loading = false;
console.log("Data Loaded:", data);
});
if (loading) {
console.log("Loading...");
}
10.7 Async/Await with Fetch & Axios
async/await
makes asynchronous code look synchronous and easier to read.
// Using Fetch
async function getPosts() {
try {
const response = await fetch("https://jsonplaceholder.typicode.com/posts");
const data = await response.json();
console.log(data);
} catch (error) {
console.error("Error:", error);
}
}
getPosts();
// Using Axios
async function getUsers() {
try {
const res = await axios.get("https://jsonplaceholder.typicode.com/users");
console.log(res.data);
} catch (error) {
console.error("Error:", error);
}
}
getUsers();
10.8 HTTP Methods with Fetch & Axios
APIs often require different HTTP methods:
- GET → Retrieve data
- POST → Create new data
- PUT → Update/replace existing data
- PATCH → Partially update existing data
- DELETE → Remove data
// ----------------------
// GET
fetch("https://jsonplaceholder.typicode.com/posts/1")
.then(res => res.json())
.then(data => console.log("GET:", data));
axios.get("https://jsonplaceholder.typicode.com/posts/1")
.then(res => console.log("GET:", res.data));
// ----------------------
// POST
fetch("https://jsonplaceholder.typicode.com/posts", {
method: "POST",
headers: {"Content-Type": "application/json"},
body: JSON.stringify({ title: "New Post", body: "Hello World", userId: 1 })
})
.then(res => res.json())
.then(data => console.log("POST:", data));
axios.post("https://jsonplaceholder.typicode.com/posts", {
title: "New Post", body: "Hello World", userId: 1
})
.then(res => console.log("POST:", res.data));
// ----------------------
// PUT (replace whole resource)
fetch("https://jsonplaceholder.typicode.com/posts/1", {
method: "PUT",
headers: {"Content-Type": "application/json"},
body: JSON.stringify({ id: 1, title: "Updated", body: "Updated Content", userId: 1 })
})
.then(res => res.json())
.then(data => console.log("PUT:", data));
axios.put("https://jsonplaceholder.typicode.com/posts/1", {
id: 1, title: "Updated", body: "Updated Content", userId: 1
})
.then(res => console.log("PUT:", res.data));
// ----------------------
// PATCH (update only some fields)
fetch("https://jsonplaceholder.typicode.com/posts/1", {
method: "PATCH",
headers: {"Content-Type": "application/json"},
body: JSON.stringify({ title: "Partially Updated Title" })
})
.then(res => res.json())
.then(data => console.log("PATCH:", data));
axios.patch("https://jsonplaceholder.typicode.com/posts/1", {
title: "Partially Updated Title"
})
.then(res => console.log("PATCH:", res.data));
// ----------------------
// DELETE
fetch("https://jsonplaceholder.typicode.com/posts/1", { method: "DELETE" })
.then(() => console.log("Deleted with Fetch"));
axios.delete("https://jsonplaceholder.typicode.com/posts/1")
.then(() => console.log("Deleted with Axios"));
10.9 Best Practices
- Always handle errors with
try...catch
or catch()
.
- Show loading indicators for better user experience.
- Use
async/await
for cleaner code.
- Keep API URLs in a config file or environment variables.
- Cache responses when possible to avoid unnecessary network calls.
- Use
Axios interceptors
for authentication tokens and global error handling.
Mini Project: User List App
Create a small program that fetches user data from an API and displays names in the console.
Handle loading states, errors, and use async/await
for better readability.
async function fetchUsers() {
console.log("Loading users...");
try {
const res = await fetch("https://jsonplaceholder.typicode.com/users");
const users = await res.json();
console.log("Users Loaded:");
users.forEach(user => console.log(user.name));
} catch (error) {
console.error("Failed to fetch users:", error);
}
}
fetchUsers();
React useContext Hook
The useContext
hook in React provides a way to pass data through the component
tree
without manually passing props at every level (prop drilling).
It makes your code cleaner and more efficient when multiple components need the same data.
11.1 Introduction to useContext
The useContext
hook is used to consume values from a React
Context
.
Context is designed to share data like theme, authentication, or language across the app.
It works in combination with React.createContext
and
Context.Provider
.
import React, { useContext, createContext } from "react";
const ThemeContext = createContext("light");
function App() {
return (
<ThemeContext.Provider value="dark">
<Toolbar />
</ThemeContext.Provider>
);
}
function Toolbar() {
const theme = useContext(ThemeContext);
return <h1>Current theme: {theme}</h1>;
}
Task: Create a context for "language" and display it inside a child
component using useContext
.
11.2 Creating Context
You can create context using React.createContext()
.
The context object comes with a Provider
and Consumer
.
import { createContext } from "react";
const UserContext = createContext(null);
export default UserContext;
Task: Create a UserContext
that stores username and email.
11.3 Using Context.Provider
The Provider
component makes data available to all child components.
You wrap your component tree with the provider and set its value
prop.
import UserContext from "./UserContext";
function App() {
const user = { name: "Alice", email: "alice@example.com" };
return (
<UserContext.Provider value={user}>
<Dashboard />
</UserContext.Provider>
);
}
Task: Wrap your app with UserContext.Provider
and pass user
details.
11.4 Consuming Context with useContext
The useContext
hook allows you to consume context values directly.
It avoids using the older Context.Consumer
syntax, making the code shorter and
cleaner.
import React, { useContext } from "react";
import UserContext from "./UserContext";
function Dashboard() {
const user = useContext(UserContext);
return <h2>Welcome, {user.name}! Your email is {user.email}</h2>;
}
Task: Consume the UserContext
in multiple components.
11.5 Nested Contexts
You can use multiple contexts in the same application.
For example, a ThemeContext
for UI theme and a UserContext
for
user info.
const ThemeContext = createContext("light");
const UserContext = createContext({});
function App() {
return (
<ThemeContext.Provider value="dark">
<UserContext.Provider value={{ name: "Bob" }}>
<Profile />
</UserContext.Provider>
</ThemeContext.Provider>
);
}
function Profile() {
const theme = useContext(ThemeContext);
const user = useContext(UserContext);
return <p>User: {user.name}, Theme: {theme}</p>;
}
Task: Combine ThemeContext
and UserContext
in one
component.
11.6 Best Practices
- Use context for global data like theme, auth, or settings.
- Don’t overuse context; for local state, use
useState
.
- Keep context values simple (avoid passing huge objects).
- Split contexts if they handle unrelated data.
- Combine
useContext
with custom hooks for cleaner code.
Mini Project: Theme Switcher
Build a small React app where you use useContext
to manage dark/light themes.
A button toggles between themes, and child components automatically update.
import React, { useState, useContext, createContext } from "react";
const ThemeContext = createContext();
function App() {
const [theme, setTheme] = useState("light");
return (
<ThemeContext.Provider value={{ theme, setTheme }}>
<Header />
<Content />
</ThemeContext.Provider>
);
}
function Header() {
const { theme, setTheme } = useContext(ThemeContext);
return (
<button onClick={() => setTheme(theme === "light" ? "dark" : "light")}>
Toggle Theme
</button>
);
}
function Content() {
const { theme } = useContext(ThemeContext);
return <h1>Current Theme: {theme}</h1>;
}
export default App;
Redux
Redux is a predictable state container for JavaScript applications.
It helps manage global state in large-scale apps, making data flow consistent and debugging
easier.
Redux is often used with React but works with any JavaScript framework.
12.1 Introduction to Redux
Redux provides a centralized store that holds the state of your application.
Instead of passing props deeply, components can access the state directly from the store.
The main idea is: Single Source of Truth.
// Install redux before using
// npm install redux react-redux
// Simple Redux store
import { createStore } from "redux";
function counterReducer(state = 0, action) {
switch (action.type) {
case "INCREMENT":
return state + 1;
case "DECREMENT":
return state - 1;
default:
return state;
}
}
const store = createStore(counterReducer);
console.log(store.getState()); // 0
Task: Create a simple Redux store with a counter reducer and test
increment/decrement actions.
12.2 Core Concepts (Store, Actions, Reducers)
Redux is built on three core principles:
- Store: Holds the entire state of the app.
- Actions: Plain objects that describe "what happened".
- Reducers: Functions that take the current state and action, then return
a new state.
// Action
const increment = { type: "INCREMENT" };
// Reducer
function counterReducer(state = 0, action) {
if (action.type === "INCREMENT") return state + 1;
return state;
}
// Store
const store = createStore(counterReducer);
store.dispatch(increment);
console.log(store.getState()); // 1
Task: Write an action for "RESET" and handle it in the reducer.
12.3 Redux Workflow
Redux follows a unidirectional data flow:
- User interacts with the UI.
- An Action is dispatched.
- The Reducer updates the state based on the action.
- The Store notifies the UI of the updated state.
store.dispatch({ type: "INCREMENT" }); // Dispatch action
console.log(store.getState()); // Updated state
Task: Draw a diagram showing the Redux data flow (UI → Action → Reducer →
Store → UI).
12.4 Redux with React
To use Redux with React, install react-redux
and use Provider
and
hooks like useSelector
and useDispatch
.
import React from "react";
import { Provider, useSelector, useDispatch } from "react-redux";
function Counter() {
const count = useSelector(state => state);
const dispatch = useDispatch();
return (
<div>
<h2>Count: {count}</h2>
<button onClick={() => dispatch({ type: "INCREMENT" })}>+</button>
<button onClick={() => dispatch({ type: "DECREMENT" })}>-</button>
</div>
);
}
function App({ store }) {
return (
<Provider store={store}>
<Counter />
</Provider>
);
}
Task: Build a React counter app using Redux.
12.5 Redux Toolkit (RTK)
Redux Toolkit simplifies Redux setup with less boilerplate.
It provides configureStore
and createSlice
.
import { configureStore, createSlice } from "@reduxjs/toolkit";
const counterSlice = createSlice({
name: "counter",
initialState: 0,
reducers: {
increment: (state) => state + 1,
decrement: (state) => state - 1,
},
});
export const { increment, decrement } = counterSlice.actions;
const store = configureStore({ reducer: counterSlice.reducer });
export default store;
Task: Rewrite your counter app using Redux Toolkit.
12.6 Middleware (Redux Thunk, Saga)
Middleware extends Redux to handle async logic like API calls.
Common middleware:
- Redux Thunk: Handles async functions inside actions.
- Redux Saga: Uses generator functions for side effects.
// Example with Redux Thunk
import { configureStore, createSlice } from "@reduxjs/toolkit";
import thunk from "redux-thunk";
const dataSlice = createSlice({
name: "data",
initialState: [],
reducers: {
setData: (state, action) => action.payload,
},
});
export const { setData } = dataSlice.actions;
const fetchData = () => async (dispatch) => {
const response = await fetch("https://jsonplaceholder.typicode.com/posts");
const data = await response.json();
dispatch(setData(data));
};
const store = configureStore({
reducer: dataSlice.reducer,
middleware: [thunk],
});
export default store;
Task: Use Redux Thunk to fetch data and display it in a component.
12.7 Best Practices
- Use Redux only when state is shared across many components.
- Prefer Redux Toolkit over manual setup.
- Keep reducers pure and avoid side effects inside them.
- Use middleware for async tasks (API calls).
- Break large slices into smaller ones for better maintainability.
Mini Project: Todo App with Redux
Create a Todo App that:
- Uses Redux Toolkit for state management
- Adds and removes todos
- Marks todos as completed
- Stores todos in a global store
import { createSlice, configureStore } from "@reduxjs/toolkit";
import { Provider, useSelector, useDispatch } from "react-redux";
const todoSlice = createSlice({
name: "todos",
initialState: [],
reducers: {
addTodo: (state, action) => [...state, { text: action.payload, completed: false }],
toggleTodo: (state, action) =>
state.map((todo, i) => i === action.payload ? { ...todo, completed: !todo.completed } : todo),
removeTodo: (state, action) => state.filter((_, i) => i !== action.payload),
},
});
const { addTodo, toggleTodo, removeTodo } = todoSlice.actions;
const store = configureStore({ reducer: todoSlice.reducer });
function TodoApp() {
const todos = useSelector(state => state);
const dispatch = useDispatch();
let input;
return (
<div>
<input ref={(node) => (input = node)} />
<button onClick={() => { dispatch(addTodo(input.value)); input.value=""; }}>Add</button>
<ul>
{todos.map((todo, i) => (
<li key={i} style={{ textDecoration: todo.completed ? "line-through" : "none" }}>
{todo.text}
<button onClick={() => dispatch(toggleTodo(i))}>Toggle</button>
<button onClick={() => dispatch(removeTodo(i))}>Remove</button>
</li>
))}
</ul>
</div>
);
}
function App() {
return (
<Provider store={store}>
<TodoApp />
</Provider>
);
}
export default App;
React Class Components
Class Components in React are ES6 classes that extend from React.Component
.
They allow you to use state, lifecycle methods, and
render() to return UI. Although Functional Components with hooks are
now more common, Class Components are still widely used in legacy and large projects.
13.1 Introduction to Class Components
A class component must extend React.Component
and include a
render()
method that returns JSX.
import React, { Component } from "react";
class Welcome extends Component {
render() {
return <h1>Hello, World from Class Component!</h1>;
}
}
export default Welcome;
Task: Create a class component named Greeting
that displays
"Welcome to React!".
13.2 Rendering UI with render()
Every class component must have a render()
method which returns JSX.
This is how the UI is displayed.
class Message extends Component {
render() {
return (
<div>
<h2>This is rendered from a Class Component</h2>
</div>
);
}
}
Task: Create a Profile
class component that renders your name
and age inside a <div>.
13.3 Constructor & State
State in class components is usually initialized in the constructor()
method.
this.state
holds component data, and it can be updated using
this.setState()
.
class Counter extends Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}
render() {
return (
<h2>Count: {this.state.count}</h2>
);
}
}
Task: Create a Counter class component with initial count = 5.
13.4 Props in Class Components
Props are passed from a parent component and accessed using this.props
.
class Welcome extends Component {
render() {
return <h1>Hello, {this.props.name}!</h1>;
}
}
// Usage
<Welcome name="Alice" />
Task: Create a class component User
that accepts
name
and age
as props and displays them.
13.5 Event Handling
Events in class components are handled using methods, and you must bind this
if
not using arrow functions.
class ButtonClick extends Component {
constructor(props) {
super(props);
this.state = { message: "Not Clicked" };
this.handleClick = this.handleClick.bind(this);
}
handleClick() {
this.setState({ message: "Button Clicked!" });
}
render() {
return (
<div>
<p>{this.state.message}</p>
<button onClick={this.handleClick}>Click Me</button>
</div>
);
}
}
Task: Create a button that updates text when clicked.
13.6 Lifecycle Methods
Lifecycle methods are special methods in Class Components:
componentDidMount()
– Runs after the component mounts (good for API calls).
componentDidUpdate()
– Runs after state/props update.
componentWillUnmount()
– Runs before component is removed (cleanup).
class LifecycleDemo extends Component {
componentDidMount() {
console.log("Component Mounted");
}
componentDidUpdate() {
console.log("Component Updated");
}
componentWillUnmount() {
console.log("Component Unmounted");
}
render() {
return <h2>Lifecycle Demo</h2>;
}
}
13.7 Updating State
State must always be updated using this.setState()
to trigger a re-render.
class Counter extends Component {
constructor(props) {
super(props);
this.state = { count: 0 };
}
increment = () => {
this.setState({ count: this.state.count + 1 });
}
render() {
return (
<div>
<h2>Count: {this.state.count}</h2>
<button onClick={this.increment}>+1</button>
</div>
);
}
}
13.8 Conditional Rendering
You can conditionally render elements based on state or props.
class LoginStatus extends Component {
constructor(props) {
super(props);
this.state = { isLoggedIn: true };
}
render() {
return this.state.isLoggedIn ?
<h2>Welcome Back!</h2> :
<h2>Please Login</h2>;
}
}
13.9 Class vs Function Components
Class Components:
- Use
this.state
and this.setState
- Have lifecycle methods
- More verbose
Function Components (with Hooks):
- Use
useState
, useEffect
, and other hooks
- Shorter and easier to write
- Modern React standard
Mini Project: Class-based Todo App
Create a Todo App with Class Components that:
- Stores todos in state
- Adds new todos
- Deletes todos
- Conditionally renders "No todos left" if empty
class TodoApp extends Component {
constructor(props) {
super(props);
this.state = { todos: [], input: "" };
}
handleChange = (e) => {
this.setState({ input: e.target.value });
}
addTodo = () => {
this.setState({
todos: [...this.state.todos, this.state.input],
input: ""
});
}
render() {
return (
<div>
<h2>Todo List</h2>
<input value={this.state.input} onChange={this.handleChange} />
<button onClick={this.addTodo}>Add</button>
<ul>
{this.state.todos.length === 0
? <li>No todos left</li>
: this.state.todos.map((todo, i) => <li key={i}>{todo}</li>)}
</ul>
</div>
);
}
}
Advanced Topics
In modern React and frontend development, advanced UI/UX patterns help improve performance,
scalability, and user experience. Here, we will explore some key concepts such as toast
notifications,
infinite scroll, loaders, pagination, modals, file uploads, performance optimizations, and
error boundaries.
14.1 Toast Notifications
Toast notifications are small, temporary pop-ups that show success, error, or informational
messages.
Libraries like react-toastify
make it very easy to implement.
import { ToastContainer, toast } from 'react-toastify';
import 'react-toastify/dist/ReactToastify.css';
function App() {
const notify = () => toast.success("Data saved successfully!");
return (
<div>
<button onClick={notify}>Show Toast</button>
<ToastContainer />
</div>
);
}
Task: Create success and error toasts for form submission.
14.2 Infinite Scroll
Infinite scrolling loads content as the user scrolls, instead of pagination.
This is useful for feeds (like Instagram, Twitter).
import { useState, useEffect } from "react";
function InfiniteScroll() {
const [items, setItems] = useState(Array.from({ length: 20 }));
const loadMore = () => {
setItems(prev => [...prev, ...Array.from({ length: 10 })]);
};
useEffect(() => {
const handleScroll = () => {
if (window.innerHeight + window.scrollY >= document.body.offsetHeight) {
loadMore();
}
};
window.addEventListener("scroll", handleScroll);
return () => window.removeEventListener("scroll", handleScroll);
}, []);
return <ul>{items.map((_, i) => <li key={i}>Item {i+1}</li>)}</ul>;
}
Task: Implement infinite scroll to load 10 items at a time.
14.3 Loading Bar / Spinner
Loaders/spinners indicate progress while data is being fetched or processed.
function Loader() {
return <div className="spinner">Loading...</div>;
}
Task: Display a spinner while fetching API data.
14.4 Pagination
Pagination divides large data sets into smaller pages for performance and clarity.
function Pagination({ totalPages, currentPage, onPageChange }) {
return (
<div>
{Array.from({ length: totalPages }).map((_, i) => (
<button
key={i}
onClick={() => onPageChange(i+1)}
disabled={currentPage === i+1}
>{i+1}</button>
))}
</div>
);
}
Task: Implement pagination for a student list.
14.5 Modal & Dialog Handling
Modals are overlays that display information or forms on top of the main UI.
function Modal({ open, onClose }) {
if (!open) return null;
return (
<div className="overlay">
<div className="modal">
<h2>Modal Content</h2>
<button onClick={onClose}>Close</button>
</div>
</div>
);
}
Task: Create a modal that opens on button click and closes when clicked
outside.
14.6 File Upload with Progress
File uploads can display progress bars for better UX. Libraries like Axios support tracking
progress.
import axios from "axios";
function uploadFile(file) {
const formData = new FormData();
formData.append("file", file);
axios.post("/upload", formData, {
onUploadProgress: (progressEvent) => {
let percent = Math.round((progressEvent.loaded * 100) / progressEvent.total);
console.log(percent + "% uploaded");
}
});
}
Task: Upload a file and show progress percentage.
14.7 Debouncing & Throttling
These are performance techniques for event handling.
Debounce: Trigger action after user stops typing.
Throttle: Limit action execution within a fixed interval.
// Debounce Example
function debounce(fn, delay) {
let timer;
return function(...args) {
clearTimeout(timer);
timer = setTimeout(() => fn.apply(this, args), delay);
};
}
// Throttle Example
function throttle(fn, limit) {
let inThrottle;
return function(...args) {
if (!inThrottle) {
fn.apply(this, args);
inThrottle = true;
setTimeout(() => inThrottle = false, limit);
}
};
}
Task: Implement debounce for search input and throttle for window resize.
14.8 Lazy Loading & Code Splitting
Lazy loading loads components only when needed. Code splitting reduces bundle size.
import React, { Suspense, lazy } from "react";
const LazyComponent = lazy(() => import("./HeavyComponent"));
function App() {
return (
<Suspense fallback={<div>Loading...</div>}>
<LazyComponent />
</Suspense>
);
}
Task: Lazy load a heavy chart component in React.
14.9 Error Boundaries
Error Boundaries catch JavaScript errors in components and prevent breaking the whole app.
Only available in class components.
class ErrorBoundary extends React.Component {
constructor(props) {
super(props);
this.state = { hasError: false };
}
static getDerivedStateFromError() {
return { hasError: true };
}
componentDidCatch(error, errorInfo) {
console.error("Error caught:", error, errorInfo);
}
render() {
if (this.state.hasError) {
return <h2>Something went wrong.</h2>;
}
return this.props.children;
}
}
Task: Wrap a component with ErrorBoundary
and trigger an error.
Mini Project: Social Media Feed
Build a mini social media feed with the following:
- Use Toast to show new post success.
- Load posts with Infinite Scroll.
- Show Spinner while fetching.
- Paginate comments with Pagination.
- Open post details in a Modal.
- Allow File Upload with progress for profile pictures.
- Use Debounce for search bar.
- Lazy Load heavy analytics component.
- Wrap app with Error Boundary.
Deployment
Once your React or JavaScript project is ready, the next step is
deployment.
Deployment means taking your local project and making it available online so that others can
use it.
There are different platforms to deploy your apps like GitHub Pages, Netlify,
Vercel, and Firebase Hosting.
15.1 Build Process (npm run build)
Before deploying, you must build your React project. The build process optimizes your app
for production.
npm run build
This creates a build
folder containing all optimized HTML, CSS, and JavaScript
files.
Task: Run npm run build
in your project and check the
build
folder.
15.2 Deploy on GitHub Pages
GitHub Pages is a free hosting service for static websites. You can easily deploy your React
app.
- Install the package:
npm install gh-pages --save-dev
- Add the following to
package.json
:
"homepage": "https://username.github.io/repository-name"
- Add scripts:
"predeploy": "npm run build",
"deploy": "gh-pages -d build"
- Run
npm run deploy
Your app will be live at your GitHub Pages URL.
15.3 Deploy on Netlify
Netlify provides free hosting with continuous deployment from GitHub.
- Create an account on Netlify
- Connect your GitHub repository
- Netlify will auto-detect React and set
npm run build
as the build command
- Deploy and get your app live at
https://your-app-name.netlify.app
15.4 Deploy on Vercel
Vercel is another popular platform for React and Next.js apps.
- Install Vercel CLI (optional):
npm i -g vercel
- Create an account at Vercel
- Import your GitHub repo
- Vercel will detect React and deploy automatically
- Your app will be live at
https://your-app-name.vercel.app
15.5 Deploy on Firebase Hosting
Firebase Hosting by Google provides fast and secure static hosting.
- Install Firebase CLI:
npm install -g firebase-tools
- Login:
firebase login
- Initialize project:
firebase init
- Choose Hosting and set
build
as the public directory
- Deploy:
firebase deploy
Your app will be live at https://your-project-id.web.app
.
Mini Project: Deploy Your App
Take a simple React project (like a Todo app), run npm run build
, and deploy it
on one of the platforms above.
Share the live link with your friends!
React Tasks
Practice makes you a pro in React! Below are different React tasks and
mini-projects
that will help you understand JSX, props, state, hooks, routing, and state management step
by step.
Each task builds on the previous concepts.
16.1 JSX Tasks
JSX allows you to write HTML-like syntax inside JavaScript. Tasks:
- Create a React component that displays a heading and a paragraph using JSX.
- Use JavaScript expressions inside JSX (like showing current year).
function App() {
const year = new Date().getFullYear();
return (
<div>
<h1>Hello JSX</h1>
<p>Year: {year}</p>
</div>
);
}
16.2 Props & Components Task
Props are used to pass data from parent to child components.
- Create a
Card
component that takes title
and
description
as props.
- Render multiple
Card
components in App
.
function Card({ title, description }) {
return <div><h2>{title}</h2><p>{description}</p></div>;
}
16.3 State & useState Hook Tasks
The useState
hook lets you manage component state.
- Create a counter app with increment and decrement buttons.
- Create a toggle button that shows/hides text.
const [count, setCount] = useState(0);
16.4 Conditional Rendering Task
Show or hide elements based on conditions.
- Create a login/logout button that switches text based on state.
{isLoggedIn ? <p>Welcome!</p> : <p>Please log in</p>}
16.5 List Rendering Tasks
Render arrays dynamically in React.
- Display a list of fruits using
map()
.
{fruits.map(fruit => <li key={fruit}>{fruit}</li>)}
16.6 Form Handling Tasks
Manage input fields and form submissions.
- Create a form with name and email input fields.
- Show the entered values on submit.
16.7 useEffect Hook Tasks
The useEffect
hook handles side effects like fetching data or timers.
- Log a message when the component mounts.
- Fetch data from an API and display it.
16.8 Context API Tasks
Context API helps share data without prop drilling.
- Create a theme context with light/dark mode.
- Toggle the theme from a button.
16.9 useReducer Hook Tasks
useReducer
is great for managing complex state.
- Build a counter with
useReducer
.
- Manage a todo list with
useReducer
.
16.10 Custom Hooks Tasks
Create reusable logic with custom hooks.
- Build a
useLocalStorage
hook.
- Build a
useFetch
hook.
16.11 React Router Basics Tasks
React Router allows navigation between pages.
- Create routes: Home, About, and Contact.
- Use
Link
to navigate between pages.
16.12 React Router Advanced Tasks
Advanced concepts include nested routes and protected routes.
- Create a dashboard with nested routes.
- Protect a route so only logged-in users can access it.
16.13 Redux / Zustand State Management Tasks
For larger apps, use Redux or Zustand for global state management.
- Create a global counter with Redux.
- Build a store with Zustand for managing todos.
16.14 Toast Notifications Tasks
Use libraries like react-toastify
to show notifications.
- Show a toast message when a form is submitted.
16.15 Pagination Tasks
Split data into pages.
- Fetch 100 items and show 10 per page with next/prev buttons.
16.16 Search & Filter List Tasks
Implement search and filtering.
- Create a search bar that filters a list of names.
16.17 Loading Spinner / Progress Bar Tasks
Show loading states for better UX.
- Show a spinner while fetching data from API.
16.18 Infinite Scroll Project
Build an infinite scrolling list using React and API fetching.
16.19 Weather App Project
Use an open weather API to build a weather forecast app.
16.20 Movie Search App Project
Fetch movies from OMDB API and display search results.
16.21 Todo App Project
Classic React project to practice CRUD operations.
16.22 Expense Tracker Project
Build an expense tracker with income/expense charts.
16.23 Tic Tac Toe Game Project
Build a two-player Tic Tac Toe game in React.
16.24 Rock-Paper-Scissors Game Project
Create a fun game where the user plays against the computer.