Internet Vs World Wide Web (WWW)
Internet Vs World Wide Web (WWW)
● Key difference:
● Request-Response model:
● Stateless protocol:
○ Each request is independent; server does not store client state between
requests.
● HTTP Headers:
3. Client-Server Architecture
● Client:
● Server:
● How it works:
● Advantages:
○ Centralized resources.
● Disadvantages:
● Why needed:
● Working:
● Types:
6. Ports
● Definition:
○ Range: 0–65535.
● Common ports:
○ HTTP: 80
○ HTTPS: 443
○ FTP: 21
○ SSH: 22
● Why needed:
7. HTML Basics
● HTML (HyperText Markup Language):
8. Semantic HTML
● Purpose:
● Benefits:
● It provides everything needed for JavaScript code execution outside of the language
itself, such as:
○ Memory allocation
2. What is V8 Engine?
● V8 is Google's open-source JavaScript engine.
● Written in C++, it compiles JavaScript directly to machine code for fast execution.
2. Compilation: Converts AST into optimized machine code using Just-In-Time (JIT)
compilation.
2. Heap
Each component works together to execute JavaScript code, especially asynchronous code
(like setTimeout, fetch, etc.).
✅ 1. Call Stack
The Call Stack is like a to-do list for your JavaScript code.
💡 What is it?
● A stack is a data structure that works on the Last In, First Out (LIFO) principle.
● It keeps track of function calls – when a function is called, it is pushed onto the
stack.
📌 Key Points
● Only one thing runs at a time in JavaScript (single-threaded).
🔍 Example:
function greet() {
console.log("Hello");
}
function welcome() {
greet();
console.log("Welcome");
}
welcome();
🧠 Step-by-step:
1. welcome() is pushed onto the call stack.
-> greet()
-> welcome()
✅ 2. Heap
The Heap is where objects and variables are stored in memory.
💡 What is it?
● A heap is an unstructured memory space used for storing complex data (like
arrays, objects).
● Unlike the call stack, which is structured, the heap allows data to be stored and
retrieved freely.
🔍 Example:
const person = {
name: "Ali",
age: 21
};
● In the call stack, only a reference (pointer) to the memory address of this object is
kept.
Web APIs are extra features given by the browser that allow JavaScript to interact
with the web page, the user, and the internet.
💡 What is it?
● These are APIs provided by the environment (browser or Node.js) to run tasks
asynchronously.
● Examples include:
○ setTimeout()
○ AJAX/fetch
JavaScript itself doesn't know how to handle time or DOM. The browser helps.
🔍 Example:
console.log("Start");
setTimeout(() => {
console.log("Timeout finished");
}, 1000);
console.log("End");
2. setTimeout() is called → the browser takes it to Web APIs and starts the
1-second timer.
5. Once the call stack is empty, the event loop pushes the callback into the call stack.
● This queue holds callbacks from Web APIs (like setTimeout, fetch) waiting to
be executed.
● FIFO (First In First Out) – the first task added is the first one executed.
B. Microtask Queue
● Special queue for Promises, MutationObserver, etc.
C. Event Loop
● Constantly checks:
○ If yes, → pushes a callback from the microtask/callback queue into the call
stack.
setTimeout(() => {
console.log("setTimeout");
}, 0);
Promise.resolve().then(() => {
console.log("Promise");
});
console.log("End");
🔁 Execution Order:
1. "Start" → printed.
✅ Output:
Start
End
Promise
setTimeout
📌 JavaScript alone is very basic — it can do logic (if/else, loops, math), but it
cannot interact with the real world (like showing alerts, setting timers, or
changing the web page).
● Show a popup
These tasks need help from the browser, and that's exactly what Web APIs provide.
They are created by browser makers (like Chrome, Firefox, Safari) and follow standards
from organizations like W3C.
Your code accesses them through JavaScript, but they are external tools.
✅ Timer API Runs code after a delay setTimeout(() => {...}, 1000)
or repeatedly
clicks)
✅ Storage
API
Saves data in browser
(locally)
localStorage.setItem("key", "123")
✅
Audio/Video
Controls media
elements on a web
video.play()
API page
✅ Canvas
API
Draws graphics or
games in browser
ctx.fillRect(0, 0, 100, 100)
✅
Geolocation
Finds your location
(with permission)
navigator.geolocation.getCurrentPos
ition()
API
✅
Notification
Shows desktop
notifications from the
new Notification("Hi there!")
API browser
<script>
function changeText() {
document.getElementById("text").innerText = "You clicked the
button!";
}
</script>
setTimeout(() => {
console.log("Hello after 2 seconds");
}, 2000);
console.log("End");
✅ setTimeout() is a Timer Web API — JavaScript sends it to the browser, the browser
waits, then sends the callback back to JavaScript when time is up.
It was introduced in ES6 (2015) and is often used in modern JavaScript, especially with
callbacks, array methods, and React components.
✅ Basic Syntax
🔹 Traditional Function:
function greet() {
return "Hello";
}
👆 This is called an implicit return. The result is returned automatically without needing
return.
✅ Example in setTimeout:
setTimeout(() => {
console.log("Hello after 2 seconds");
}, 2000);
● After 2 seconds, the function runs and prints "Hello after 2 seconds".
this keyword Does not bind its own Has its own this
this
Can be used as a
constructor
❌ No ✅ Yes
arguments object ❌ Not available ✅ Available
For simple callbacks ✅ Preferred 👌 Still works
✅ Important: this Binding
Arrow functions do not create their own this. Instead, they inherit this from the
surrounding code (lexical scoping).
Example:
const user = {
name: "Ali",
greet: function () {
setTimeout(() => {
console.log("Hi, " + this.name);
}, 1000);
}
};
user.greet();
● this.name refers to "Ali" because the arrow function uses this from greet(),
which belongs to user.
setTimeout(function() {
console.log("Hi, " + this.name); // ❌ undefined
}, 1000);
✅ This is why arrow functions are preferred in callbacks where you want to preserve the
parent context.
setTimeout(() => {
console.log("Hi, " + this.name);
}, 1000);
Why?
● Arrow functions do not have their own this. Instead, they use the this value from
the surrounding (lexical) scope.
● So, inside this arrow function, this.name refers to the this of the outer context
where this setTimeout is called.
Explanation:
● this inside the arrow function refers to the user object because it inherits this
from greet()'s context.
● So this.name is "Ali".
Example 2: Not working as expected in global context
setTimeout(() => {
console.log("Hi, " + this.name); // 'this' here refers to global
object (window in browsers)
}, 1000);
Output:
Hi, Global
Explanation:
If you run this in strict mode, this will be undefined and accessing this.name will print
undefined.
Explanation:
● Regular functions get their own this depending on how they are called.
● Inside setTimeout, this refers to the global object (or undefined in strict mode),
not the user object.
● So this.name is undefined.
What is the Event Loop in JavaScript?
Event Loop: An Event Loop in JavaScript is said to be a constantly running process that
keeps a tab on the call stack. Its main function is to check whether the call stack is empty or
not. If the call stack turns out to be empty, the event loop proceeds to execute all the
callbacks waiting in the task queue. Inside the task queue, the tasks are broadly classified
into two categories, namely micro-tasks and macro-tasks.
● But modern web apps need to handle asynchronous tasks: timers, user input,
network requests, etc.
● To handle async without blocking the main thread, JavaScript uses the Event Loop
to manage when to run code.
○ And if there are any tasks waiting in the task queues (macrotasks or
microtasks).
● If the call stack is empty and there are waiting tasks, the event loop moves the next
task from the queue to the call stack for execution.
● Web APIs: Browser or environment features like timers, network requests, DOM
events.
● Task Queues:
● Event Loop: Coordinates when tasks move from queues to the call stack.
4. Step-by-Step Flow
1. JavaScript starts running synchronous code (everything goes to call stack).
3. Once the async task finishes, its callback function is placed into the appropriate task
queue:
4. The call stack finishes running all synchronous code and becomes empty.
6. Then the event loop picks one macrotask from the macrotask queue and pushes it
to the call stack.
6. Example
console.log("Script start");
setTimeout(() => {
console.log("setTimeout");
}, 0);
Promise.resolve().then(() => {
console.log("Promise");
});
console.log("Script end");
Output:
Script start
Script end
Promise
setTimeout
Explanation:
Conclusion:
● Your original code snippet is correct as an arrow function, but
● It only works as expected if the surrounding this refers to the object that has the
name property.
● In many cases, using arrow functions inside object methods helps you keep the
correct this.
● If you want a regular function and want to keep the this of the object, you can do:
These tasks are queued and then executed one at a time on the single-threaded call
stack.
● Microtask queue
They are separate queues that the event loop processes with different priorities.
3. Macrotask Queue
Macro-tasks within an event loop: Macro-task represents some discrete and independent
work. These are always the execution of the JavaScript code and the micro-task queue is
empty. Macro-task queue is often considered the same as the task queue or the event
queue. However, the macro-task queue works the same as the task queue. The only small
difference between the two is that the task queue is used for synchronous statements
whereas the macro-task queue is used for asynchronous statements.
What it contains:
● I/O events
● setImmediate (Node.js)
● requestAnimationFrame
How it works:
● When the call stack is empty, the event loop picks the first macrotask in the queue
and pushes it to the call stack.
● Then the event loop checks the microtask queue before running the next macrotask.
4. Microtask Queue
Micro-tasks within an event loop: A micro-task is said to be a function that is executed
after the function or program which created it exits and only if the JavaScript execution stack
is empty, but before returning control to the event loop being used by the user agent to drive
the script's execution environment.
What it contains:
● queueMicrotask()
How it works:
● Microtasks run immediately after the currently executing script finishes and
before the event loop processes the next macrotask.
● The event loop drains the entire microtask queue before moving back to the
macrotask queue.
7. Example to Illustrate
console.log("Script start");
setTimeout(() => {
console.log("setTimeout (macrotask)");
}, 0);
Promise.resolve()
.then(() => {
console.log("Promise 1 (microtask)");
})
.then(() => {
console.log("Promise 2 (microtask)");
});
console.log("Script end");
Execution flow:
Output order:
Script start
Script end
Promise 1 (microtask)
Promise 2 (microtask)
setTimeout (macrotask)
Explanation:
● The synchronous code runs first: "Script start", then "Script end".
8. Additional Notes
● Because microtasks run first, they can cause UI blocking if they keep adding more
microtasks.
● Understanding this helps write better asynchronous code and avoid UI freezes.
Promises in JavaScript
✅ What is a Promise?
● A Promise is an object that represents the eventual completion (or failure) of an
asynchronous operation.
● It lets you write asynchronous code that’s easier to read and manage than traditional
callbacks.
✅ Promise States
A Promise can be in one of these states:
State Meaning
✅ Creating a Promise
const myPromise = new Promise((resolve, reject) => {
if(success) {
resolve("Task completed!");
} else {
reject("Task failed!");
});
✅ Using a Promise
myPromise
.then(result => {
console.log("Success:", result);
})
.catch(error => {
console.log("Error:", error);
});
setTimeout(() => {
if(success) {
resolve("Data received!");
} else {
reject("Error occurred");
}, 2000);
});
fakeApiCall()
What is async/await?
Async and Await in JavaScript is used to simplify handling asynchronous operations using
promises. By enabling asynchronous code to appear synchronous, they enhance code
readability and make it easier to manage complex asynchronous flows.
1. async Function
The async function allows us to write promise-based code as if it were synchronous. This
ensures that the execution thread is not blocked. Async functions always return a promise. If
a value is returned that is not a promise, JavaScript automatically wraps it in a resolved
promise.
Syntax:
// Code here
Example:
return "Hello";
}
2. await Expression
The await keyword is used to wait for a promise to resolve. It can only be used within an
async block. Await makes the code wait until the promise returns a result, allowing for
cleaner and more manageable asynchronous code.
● It pauses the execution of the function until the Promise is resolved or rejected,
and returns the resolved value.
● If the Promise is rejected, it throws an error that you can catch with a try/catch
block.
Syntax:
● The await expression unwraps the value from the promise when it resolves.
● It does not block the entire thread but only pauses the execution of the async
function, allowing other tasks to run.
Example:
console.log(greeting);
greet(); // "Hello"
● The await here waits for the Promise.resolve("Hello") to resolve before
logging it.
try {
console.log(data);
} catch (error) {
console.log("Error:", error);
fetchData();
Explanation:
● Once the response is resolved, we use await again to parse the JSON data.
● If any step fails (for example, if the network request fails), the error is caught by the
catch() block.
2. Error Handling: With async/await, error handling becomes simpler with
try/catch.
3. Better Debugging: Asynchronous errors are easier to trace because they behave
like normal errors in a synchronous function.
function fetchData() {
return fetch('https://jsonplaceholder.typicode.com/posts')
fetchData();
With async/await:
try {
console.log(data);
} catch (error) {
console.log("Error:", error);
fetchData();
Key Differences:
1. Readability: async/await makes the code easier to read and closer to how
synchronous code works.
try {
} catch (error) {
console.log("Error:", error);
fetchData();
Here, response2 will not execute until response1 has finished resolving.
Scoping in JavaScript
✅ What is Scoping?
Scoping refers to the visibility or accessibility of variables within different parts of your
code. It determines where a variable can be accessed or modified.
There are two main types of scopes in JavaScript:
javascript
Copy
function showGlobal() {
function localScopeExample() {
● localVar is only accessible inside the function where it is declared. Outside the
function, it cannot be accessed.
1.3 Block Scope (ES6)
● Introduced with let and const (in ES6), block scope means that variables
declared with let or const inside blocks (like loops or conditionals) are only
available within that block.
if (true) {
● blockScoped is only available within the block (the if statement in this case).
2. Hoisting in JavaScript
✅ What is Hoisting?
Hoisting refers to the JavaScript behavior where variable declarations (using var, let, or
const) and function declarations are moved (or hoisted) to the top of their scope during
the compilation phase before the code is executed. This means that it is possible to use
variables and functions before they are declared in the code. However, it is important to note
that only declarations are hoisted, not initializations.
● Variables declared with var are hoisted to the top of their scope (either global or
function scope).
var a = 10;
console.log(a); // Output: 10
● The declaration var a is hoisted to the top, but its assignment (a = 10) happens
only when the code is executed, so the first console.log(a) prints undefined.
2. Step 2: The variable a is assigned the value 10 after the hoisting.
● let and const are also hoisted, but they have a special behavior called the
"temporal dead zone" (TDZ).
● The TDZ refers to the time between the beginning of the scope and the actual line
where the variable is declared and initialized.
● Variables declared with let or const are not accessible before their declaration
line. Accessing them before the declaration results in a ReferenceError.
let b = 20;
● Even though let b is hoisted, it cannot be accessed before the line where it is
initialized. This avoids issues caused by hoisting with var.
function greet() {
console.log("Hello!");
● The greet() function is hoisted to the top of its scope, so it can be invoked even
before its actual declaration.
○ The variable to which the function is assigned is hoisted, but its assignment
happens during execution.
};
● Here, myFunc is hoisted but is initially undefined. The function is only assigned
during execution, so calling it before the assignment leads to an error.
Summary
Global Scope Variables are accessible anywhere var x = 100; — accessible globally.
in the program.
Local Scope Variables are accessible only within let y = 20; — only accessible in the
the function or block. function/block
Hoisting with They are hoisted but not accessible console.log(b); let b = 20; —
let/const before declaration (TDZ). Error
● Variables declared with var are hoisted to the top of the scope, but initialized to
undefined.
Scope:
function example() {
if (true) {
console.log(x, y); // 10 20
example();
Hoisting:
● Variables declared with var are hoisted, but their value assignment happens only at
runtime.
var a = 5;
console.log(a); // Output: 5
● Here, a is hoisted, but its value is only assigned when the code is executed. Hence,
the first console.log(a) prints undefined.
Redeclaration:
var a = 10;
console.log(a); // Output: 20
● Variables declared with let are hoisted but not initialized until the line of
declaration, leading to the temporal dead zone (TDZ).
Scope:
if (true) {
console.log(x); // Output: 10
Hoisting:
● Hoisted to the top, but not initialized until the declaration is reached, which leads to
the temporal dead zone (TDZ).
console.log(a); // Error: Cannot access 'a' before initialization
let a = 5;
● Here, the variable a is hoisted, but it cannot be accessed before its declaration
because it’s in the temporal dead zone.
Redeclaration:
● You cannot redeclare a variable declared with let in the same scope.
let a = 10;
● Cannot be reassigned once the variable is initialized. This means you cannot
change the value of the variable after it’s been declared.
● Hoisted but not initialized, just like let. The temporal dead zone applies.
Scope:
if (true) {
console.log(x); // Output: 10
Hoisting:
● Hoisted to the top, but not initialized until the declaration is reached, resulting in the
temporal dead zone.
● The variable a is hoisted, but it cannot be accessed before the const declaration,
which causes an error due to the temporal dead zone.
Reassignment:
const a = 10;
● You can modify the contents of arr because the reference to the array object is not
changing.
● But if you try to reassign arr itself (like assigning a new array), you will get an error.
1. Closures in JavaScript
✅ What is a Closure?
A closure in JavaScript is a function that retains access to its lexical scope even when
the function is executed outside that scope. In simpler terms, closures allow a function to
"remember" the variables from the scope in which it was created.
function innerFunction() {
Key Points:
● Emulating private methods: Closures are often used to create private variables
and methods.
function counter() {
return {
increment: function() {
count++;
console.log(count);
},
decrement: function() {
count--;
console.log(count);
};
myCounter.increment(); // Output: 1
myCounter.increment(); // Output: 2
myCounter.decrement(); // Output: 1
● The count variable is private and cannot be accessed directly from outside the
counter() function.
● The inner functions (increment and decrement) can access and modify the
count variable via closure.
2. Prototype Chain in JavaScript
✅ What is the Prototype Chain?
Every JavaScript object has a property called prototype, which points to another object.
The prototype chain is the series of objects that JavaScript looks through to find properties
or methods that are not directly present in an object.
● If you access a property or method on an object and the object doesn't have it,
JavaScript looks for it in the prototype of that object.
● If it's not in the prototype, it looks in the prototype's prototype, and so on, until it
reaches the Object.prototype, which is the root object.
name: "John",
greet() {
};
student.name = "Alice";
Explanation:
● greet() is defined in person, and even though it's not in student, student can
still use it because of the prototype chain.
✅ Inheritance Example:
const animal = {
eats: true
};
dog.barks = true;
● The value of this depends on how a function is called. It can refer to different
objects, depending on whether the function is invoked as a method, constructor, or
standalone function.
✅ Examples of this:
1. this in Global Context
2. this in a Method
const person = {
name: "John",
greet() {
};
● Inside a method, this refers to the object calling the method (person in this
case).
function Person(name) {
this.name = name;
● In constructor functions, this refers to the new object being created (here,
person1).
Arrow functions do not have their own this. Instead, they inherit this from their lexical
scope.
const person = {
name: "John",
greet: () => {
console.log(this.name); // 'this' refers to the global object,
not person
};
● Since arrow functions do not have their own this, they inherit this from where
they were defined, not from where they are called.
● It’s created when a function is defined within another function and retains access to
the outer function's variables.
1. Debounce:
✅ What is Debounce?
● Debouncing is a technique used to limit the rate at which a function is executed.
● It ensures that the function is executed only after a certain amount of idle time (or
delay) has passed since the last time the function was called.
● Essentially, it delays the execution of the function until a specified period has
elapsed since the last event.
● Window resizing: For example, when resizing the window, you don’t want to trigger
expensive calculations or UI updates on every resize event. You can wait until the
user stops resizing the window.
✅ Example Code for Debounce:
Let’s take a search input scenario:
function search(query) {
let timer;
return function(...args) {
};
document.getElementById('searchInput').addEventListener('input',
(event) => {
debouncedSearch(event.target.value);
});
Explanation:
● When the user types in the search box, the debouncedSearch function is called.
● Each keystroke cancels the previous timer and sets a new one, so the search
function is only called 500ms after the user stops typing.
2. If the event is triggered again before the timer ends, the previous timer is cleared,
and a new one is started.
3. The function is executed only when the event stops for the specified delay.
✅ When to Use Debounce:
● Form validation or autocomplete for search inputs.
● Resizing or scrolling events where you want to delay action until the user stops
interacting.
2. Throttle:
✅ What is Throttle?
● Throttling ensures that a function is executed at most once in a specified time
interval.
● Resize events: If you want to resize an element in sync with the window, but avoid
continuous resizing, throttling ensures it only happens at regular intervals.
function loadMoreContent() {
let lastTime = 0;
return function(...args) {
lastTime = now;
func(...args);
}
};
window.addEventListener('scroll', throttledLoadMore);
Explanation:
2. If the function is called again before the delay has passed, it is ignored.
3. The function is called once every fixed interval (e.g., every 1000ms).
● Resize events, where you want to run an action (e.g., adjust the layout) at fixed
intervals, rather than on every resize.
This means functions can be passed around and manipulated like variables.
console.log("Hello!");
function caller(fn) {
return function(number) {
};
console.log(twice(5)); // Output: 10
● This returned function remembers the factor via closure (next topic).
● Even if the outer function returns and its execution context is popped off the
call stack, those variables are not garbage collected as long as the inner function
(closure) still references them.
● This means closures keep variables “alive” in memory for as long as the closure
exists.
count++;
console.log(count);
};
counter(); // Output: 1
counter(); // Output: 2
● Even though outer() finished executing, the variable count remains in memory
because the returned function inner() closes over it.
● Each call to counter() updates and remembers the same count variable.
Example:
callback();
● Here, the second argument is a callback function that runs after greeting.
3. Decorators
● A decorator is a function that wraps another function to modify or enhance its
behavior without changing the original function’s code.
Simple Example:
function logDecorator(fn) {
return function(...args) {
return fn(...args);
};
function sayHi(name) {
decoratedSayHi("Ali");
// Logs:
// Hi Ali
REST API
REST API stands for REpresentational State Transfer API. It is a type of API (Application
Programming Interface) that allows communication between different systems over the
internet. REST APIs work by sending requests and receiving responses, typically in JSON
format, between the client and server.
REST APIs use HTTP methods (such as GET, POST, PUT, DELETE) to define actions that
can be performed on resources. These methods align with CRUD (Create, Read, Update,
Delete) operations.
A request is sent from the client to the server via a web URL, using one of the HTTP
methods. The server then responds with the requested resource, which could be HTML,
XML, Image, or JSON, with JSON being the most commonly used format for modern web
services.
Client-Server Architecture: RESTful APIs are based on a client-server model, where the
client and server operate independently, allowing scalability.
Uniform Interface: REST APIs follow a set of conventions and constraints, such as
consistent URL paths, standardized HTTP methods, and status codes, to ensure smooth
communication.
Layered System: REST APIs can be deployed on multiple layers, which helps with
scalability and security.
1. GET:
2. POST:
3. PUT:
4. PATCH:
○ Unlike PUT, which typically requires the entire resource to be sent, PATCH
allows updating only specific fields.
○ Example: PATCH /users/1 (Update the user with ID 1, e.g., just their
email)
5. DELETE:
GET Retrieve data Fetch resources (e.g., GET /users to fetch users)
POST Create a new Add new data (e.g., POST /users to create a user)
resource
PUT Update a resource Replace data (e.g., PUT /users/1 to update user
with ID 1)
PATCH Partially update a Modify part of the data (e.g., PATCH /users/1 to
resource update part of user data)
Middleware:
In web development, middleware refers to functions that run between the request and
response cycle in a web server (e.g., Express in Node.js). Middleware can be used to handle
tasks like authentication, logging, data parsing, or handling errors before sending the final
response back to the client.
● What is CORS?
Example:
// In Express.js middleware
});
● Key Terms:
○ Preflight Request: A CORS check made by the browser before sending the
actual request, to see if the server allows it.
In simple terms:
● View: Represents the user interface (UI) and displays the data to the user.
● Controller: Handles the user input, manipulates the model, and updates the view.
1. Model:
○ The Model does not concern itself with the user interface. It only represents
and manages the data.
○ Example: In a blog application, the Post model would represent the blog post
data (title, content, author, etc.).
2. View:
○ The View is responsible for displaying the data to the user and updating the
UI.
○ It is independent of the logic and merely renders what it gets from the
controller or the model.
○ Example: In a blog application, the view would display a list of blog posts to
the user.
3. Controller:
○ The Controller acts as an intermediary between the Model and the View.
○ It processes incoming requests from the user, interacts with the Model to
retrieve or manipulate data, and then updates the View with the results.
2. The Controller receives the input from the View and processes it (e.g., validates
form data).
3. The Controller then updates the Model (e.g., adds a new post to the database).
4. After the Model is updated, the Controller refreshes the View with updated data
(e.g., show the new blog post on the page).
2. View: In the context of Express, the View is responsible for rendering HTML
templates to the user. This could be done using template engines like EJS, Pug, or
Handlebars. The View is rendered by the Controller based on the data it gets from
the Model.
JSX is a syntax extension for JavaScript used with React. It looks very similar to HTML, but
it’s actually syntactic sugar for React.createElement() calls.
What is JSX?
● React components are often written using JSX to describe the UI.
● JSX is not valid JavaScript, but React has a compiler that converts JSX into valid
JavaScript.
● Here, <h1> is HTML-like syntax inside JavaScript. When rendered, React converts
this into React.createElement('h1', null, 'Hello, World!').
function Greeting(props) {
● In this example, {props.name} is JavaScript inside JSX. React will replace it with
the value passed through props.
JSX Rules:
● Self-closing tags: Just like in HTML, JSX uses self-closing tags like <img />,
<input />.
● Attribute values in JSX are passed using camelCase, e.g., className instead of
class.
2. Props vs State
Both props and state are used to manage data in React components, but they serve
different purposes.
● Props are used to pass data from a parent component to a child component.
● Props are immutable within the child component, i.e., the child cannot modify its
props.
Example of Props:
function Greeting(props) {
}
function App() {
State
● State is used to manage data that can change over time within a component.
● Unlike props, state is mutable and can be updated by the component itself.
● State is usually used for user input, interactivity, and component-specific data.
Example of State:
function Counter() {
return (
<div>
<p>Count: {count}</p>
</div>
);
}
● State (count) starts at 0 and can be updated by calling setCount.
● Clicking the button updates the state, causing the component to re-render with the
updated value.
React Hooks are functions that allow you to use state and other React features in
functional components. Before Hooks, you could only manage state and lifecycle methods
in class components, but Hooks make it possible to do this in functional components too.
Key Hooks:
1. useState():
Example:
javascript
Copy
const [count, setCount] = useState(0); // Declare a state variable
`count` with initial value 0
○
○ count is the state, and setCount is the function used to update it.
2. useEffect():
○ Allows you to perform side effects (like fetching data or manipulating the
DOM).
○ It runs after the component renders, and you can control when it runs (e.g.,
on mount, update, or unmount).
Example:
javascript
Copy
useEffect(() => {
Example:
javascript
Copy
const value = useContext(MyContext); // Get the value from context
○
1. Functional Components:
✅ Definition:
● Functional components are simple JavaScript functions that return JSX to render the
UI.
● They are stateless by default but can use Hooks (like useState and useEffect)
to manage state and side effects in modern React.
✅ Key Characteristics:
● They are easier to read and write.
● Prior to React 16.8, functional components were stateless and could only receive
props. After the introduction of Hooks, functional components can now handle state,
lifecycle methods, and side effects.
jsx
Copy
function Greeting(props) {
function App() {
● Here, Greeting is a functional component that takes props and returns JSX.
Copy
function Counter() {
return (
<div>
<p>Count: {count}</p>
</div>
);
}
2. Class Components:
✅ Definition:
● Class components are ES6 JavaScript classes that extend React.Component.
● They were the standard way to create components in React before React 16.8,
which introduced Hooks.
● Class components can have state, lifecycle methods, and event handlers.
✅ Key Characteristics:
● They are more complex than functional components.
● They can manage state and have lifecycle methods like componentDidMount,
componentDidUpdate, etc.
Copy
render() {
function App() {
return <Greeting name="Alice" />;
Copy
constructor(props) {
super(props);
increment = () => {
};
render() {
return (
<div>
<p>Count: {this.state.count}</p>
<button onClick={this.increment}>Increase</button>
</div>
);
}