Frontend Technologies
Frontend Technologies Overview
When a browser loads a webpage, The browser creates an execution environment where it processes three core technologies: it first parses the HTML, then applies the CSS styles, and finally executes JavaScript to add behavior (e.g., animations, API calls).
HTML is the backbone of any web page. It defines the content and structure of the page.
Acts as the skeleton of a website.
It includes elements like headings (<h1> to <h6>), paragraphs (<p>), images (<img>), links (<a>), buttons (<button>), and layout containers (<div>, <section>, etc.).
CSS controls the appearance and layout of HTML elements.
Uses selectors to target HTML elements.
Defines visual rules: colors, fonts, margins, padding, borders, animations, etc.
Styling Approaches:
Inline: <div style="color: red;">
Embedded: Inside <style> tags in HTML.
External: Linked .css file using <link rel="stylesheet" href="style.css" />
JavaScript: Adds dynamic behavior, interactivity, and logic to web pages.
Responds to user events (clicks, keypress, mouse).
Manipulates the DOM: adding/removing/updating HTML elements and styles dynamically.
Enables asynchronous behavior (AJAX, Fetch API).
Common JS Frameworks/Libraries:
React, Vue, Angular, jQuery — used for component-based development and rich UIs.
JavaScript Basics
Client-side + Server-side: Initially for browsers, but evolved to backend (Node.js).
Node.js: JavaScript runtime outside the browser, built on Chrome's V8 engine.
Makes JS a full-stack language.
Single-threaded:
JavaScript uses a single-threaded model.
One task at a time on a single call stack.
Long-running tasks can block the main thread unless handled asynchronously.
Asynchronous Execution & Event Loop:
JS uses the event loop to handle asynchronous operations.
Event Loop Workflow:
Asynchronous operation (e.g., setTimeout, fetch) is delegated to Web APIs.
Uses separate threads to handle the task in the background
Once complete, the callback is queued.
Event loop moves the callback into the call stack when it’s empty.
Web Workers (in browsers): Allow real multithreading, but can’t access DOM directly.
Node.js: Uses libuv to manage async I/O operations with a thread pool. Also supports worker_threads for true multithreading.
Interpreted Language + JIT
Interpreted: Code is run line-by-line at runtime (unlike Java or C++).
JIT: Interpreted languages can sometimes be slower than compiled languages because the code needs to be translated each time it's executed. However, modern JavaScript engines employ techniques like Just-In-Time (JIT) compilation to optimize frequently executed code, bridging this performance gap significantly. Here's the process:
Initial Interpretation: The engine initially starts by interpreting the JavaScript code, similar to the traditional approach. This allows for quick startup.
Profiling: As the code runs, the engine monitors which parts of the code are executed most frequently (these are often called "hot paths").
Compilation to Machine Code: The JIT compiler then kicks in and translates these "hot" sections of JavaScript code into highly optimized machine code (the language that the computer's processor directly understands).
Caching and Re-execution: This compiled machine code is then cached. When those "hot" sections of code need to be executed again, the engine can directly run the much faster machine code instead of re-interpreting it.
Note: While AOT(Ahead-Of-Time) compilation (compiling the entire code before execution) can offer even better performance in some cases, it's not traditionally used for JavaScript in browsers
Major JavaScript engines to parse and execute JS code:
Chrome / Node.js: V8 (Written in C++, fast, JIT-based)
Firefox: SpiderMonkey
Safari: JavaScriptCore (also known as SquirrelFish/Nitro)
Optimized for Apple devices
Microsoft Edge (Chromium-based): V8
Older Microsoft Edge (pre-Chromium): Chakra
Modules in JavaScript
CommonJS (CJS): Traditional Node module system
const fs = require('fs');
module.exports = myFunction;
ESM (ECMAScript Modules): Modern JavaScript modules
import fs from 'fs';
export default myFunction;
Host Environments for JavaScript
Host Environment: Provides APIs (like document, fetch, setTimeout) that JS itself doesn’t have.
JS + Host = Full execution context.
JavaScript can run in different environments, each providing specific capabilities and APIs beyond the core JavaScript language.
Client-Side (Browser): Runs inside browser engines like Chrome's V8, Firefox's SpiderMonkey, Safari's JavaScriptCore, etc.
Interacts with the DOM (Document Object Model) to dynamically update HTML and CSS.
Provides browser-specific APIs, such as:
window, document
localStorage, sessionStorage
fetch, XMLHttpRequest
setTimeout, setInterval
Used for building interactive UIs, validating forms, handling events, and making AJAX requests.
Server-Side (Node.js): Built on Chrome’s V8 engine, but adds server-side capabilities.
Allows access to system resources and hardware:
File system (fs module)
Network and HTTP (http, https, net modules)
OS-level APIs (os, process)
Supports package management through npm (Node Package Manager).
Used for creating REST APIs, backend services, real-time apps, command-line tools, etc.
JavaScript Execution Flow
Key Components of JavaScript Execution Flow:
Code Parsing and Compilation
Parsing: The JavaScript engine starts by reading the source code and breaking it into tokens.
These tokens are then converted into an Abstract Syntax Tree (AST).
Compilation: The AST is compiled into machine code.
Execution Context Creation: JavaScript executes code within an execution context, which is a container that holds the state of the code being executed.
Global Execution Context (GEC): Created once at the beginning.
Binds the global object (window in browser, global in Node.js).
All top-level code runs in this context.
Set up `this` keyword to refer to the global object.
Function Execution Context (FEC): Created whenever a function is called. Each function gets its own context.
Each execution context has:
Variable Environment: Stores var variables and function declarations (hoisted).
Lexical Environment: Manages the scope chain, allowing access to variables in outer scopes.
Enables closures by preserving references to outer environments.
This Binding: Determines the value of this, which depends on how a function is called (e.g., method call, standalone function, arrow function).
Regular call: This is undefined or global
Method call: This is the calling object
Arrow function: Arrow functions do not have their own this, they capture this from their surrounding lexical scope.
Memory Allocation: Stack vs. Heap: JavaScript uses two memory areas:
Call Stack (LIFO): Stores execution contexts for synchronous code execution.
Each function call adds (pushes) a new context to the stack; once done, it is removed (popped).
Heap Memory (Dynamic):
For dynamic memory used to store: Objects, Arrays, Functions, Closures
Used when complex data types are created.
Execution contexts only store references (pointers) to objects in the heap.
Example:
const user = { name: "Manish", role: "Engineer" };
The object is stored in the heap, and the user variable holds a reference on the stack.
Execution Phases: The execution context goes through two phases:
Creation Phase:
Function declarations are hoisted with their entire body.
Variables declared with var are hoisted and initialized to undefined.
let/const remain uninitialized in the Temporal Dead Zone.
Variables declared with let and const are hoisted but remain in a Temporal Dead Zone (TDZ) until their declaration is evaluated.
`this` is set based on context (global, object method, etc.).
Execution Phase:
Code is executed line by line.
Variables are assigned values, and functions are invoked.
Any references to undeclared let/const variables during TDZ will throw a ReferenceError.
Call Stack: JavaScript uses a call stack to manage execution contexts:
When a function is called, a new execution context is pushed onto the stack.
When the function completes, its context is popped off, and control returns to the previous context.
The stack operates in a Last-In-First-Out (LIFO) manner.
Event Loop and Asynchronous Execution
JavaScript is single-threaded but handles asynchronous operations (e.g., setTimeout, fetch, or event listeners) using the event loop. Here's how it works:
Web APIs: Asynchronous tasks (like timers, HTTP requests, or DOM events) are handled by the browser or Node.js's Web APIs, not the JavaScript engine.
Callback Queue (Task Queue/ Macro-task Queue): When an async task completes, its callback is placed in the callback queue.
Event Loop: Moves callbacks to call stack when it's empty.
Microtask Queue: Promises and async/await callbacks go to a higher-priority microtask queue, processed before the callback queue.
Garbage Collection: JavaScript performs automatic memory management for heap memory using garbage collection (GC).
Mark-and-sweep is the most common algorithm.
GC identifies and removes objects in the heap that are no longer reachable from any active reference.
Helps prevent memory leaks, though caution is needed with circular references.
Example – Synchronous Execution
Code:
function second() { console.log('Hello there!'); } function first() { console.log('Hi there!'); second(); // Synchronous call console.log('The End'); } first();
Output:
Hi there!
Hello there!
The End
Example – Asynchronous Execution:
Code:
function second() { console.log('Hello there!'); } function first() { console.log('Hi there!'); setTimeout(second, 1000); // Asynchronous call (1-second delay) console.log('The End'); } first();
Output:
Hi there!
The End
Hello there! // (After 1 second)
Critical Rendering Path (CRP)
The CRP defines how browsers convert HTML, CSS, and JavaScript into pixels on the screen. Optimizing it improves perceived performance and user experience.
Rendering Workflow:
Parse HTML → DOM(Document Object Model)
The browser reads the HTML markup and builds the DOM (Document Object Model).
The DOM is a tree-like structure where each HTML tag is represented as a node, and the browser can manipulate and interact with this tree to render the page.
Blocking Behavior: When the browser encounters the <script> tag, it may block the rendering of the page until the resources are loaded. If the script is in the <head> and lacks an async or defer attribute, it will block the DOM construction.
async loads the script in parallel with HTML parsing, while defer ensures the script executes only after the HTML is fully parsed.
Parse CSS → CSSOM(CSS Object Model)
After parsing the HTML, the browser then parses the CSS and generates the CSSOM.
The CSSOM is a tree structure that represents the CSS styles applied to elements.
Blocking Behavior: External CSS files or <style> tags with CSS rules block rendering because the browser must fully build the CSSOM to accurately render the page's styles. If the browser encounters a <link rel="stylesheet"> tag, it waits to download and parse the CSS before proceeding.
Combine DOM and CSSOM → Render Tree
The browser combines the DOM and CSSOM to form the Render Tree.
The Render Tree represents the visual structure of the page, where each element is matched with its styles. This tree includes only the visible elements of the page.
Layout(Reflow): Once the Render Tree is built, the browser needs to calculate the layout of each element, determining its size and position on the screen.
The browser calculates the exact pixel position of each element based on the viewport size and CSS rules.
Triggered when layout-related properties are changed
Examples:
Changing the size of an element (e.g., width, height).
Adding or removing elements from the DOM.
Changing font-size or other layout-affecting properties.
document.getElementById('myElement').style.width = '200px'; // This triggers reflow
Performance impact: Reflow is expensive because it forces the browser to recalculate the layout, which can affect rendering performance, especially if it happens repeatedly.
Paint: Converts layout into actual pixels on the screen
Involves drawing text, images, borders, shadows, etc.
Repaint: Visual changes (e.g., color, visibility)
Repaint happens when the visual appearance of an element changes, but the layout does not. This is a less expensive operation compared to reflow.
Example:
Changing color (background-color, color).
Modifying visibility (e.g., visibility: hidden to visibility: visible).
Updating border-style, box-shadow, etc.
document.getElementById('myElement').style.backgroundColor = 'blue'; // This triggers repaint
Performance impact: Repaints are generally less costly than reflows since the layout doesn’t need to be recalculated, but excessive repaints (e.g., changing styles frequently) can still degrade performance.
Composite → Final visual output
Performance Metrics: The following performance metrics help measure the speed and efficiency of the rendering process:
First Paint: First pixel on screen
FCP (First Contentful Paint): The time it takes for the first piece of content (like text, images, or background color) to appear on the screen.
FCP indicates when the user sees the first visible feedback that the page is loading.
FMP (First Meaningful Paint): The time it takes for the first meaningful content to appear on the screen. This could be the main text, images, or something that conveys useful content to the user.
Example: A page might display the headline or hero image as the first meaningful content.
FMP tells users that the page is starting to become useful.
LCP (Largest Contentful Paint): The time it takes for the largest visible content (usually the main image or block of text) to load and appear on the screen.
Example: The main hero image on a page might take a few seconds to load. LCP measures when this large element is fully visible.
TTI (Time to Interactive) : The time it takes for the page to become fully interactive, meaning all JavaScript has been loaded and executed, and the user can interact with all elements (e.g., buttons, forms).
Optimization Tips:
Batch DOM changes: Instead of making changes to individual DOM elements one at a time, make all changes in one go. This minimizes the number of reflows and repaints.
// Triggers 2 reflows (slow)
element.style.width = '200px';
element.style.height = '100px';
// Single reflow (optimal)
element.style.cssText = 'width: 200px; height: 100px; margin-top: 10px; margin-bottom: 20px;';
Cache layout properties:
Some DOM properties like offsetHeight, offsetWidth, getComputedStyle(), and scrollTop, force the browser to recalculate the layout (trigger a reflow) every time they are accessed.
So, if we read such a property multiple times (especially in a loop), the browser might perform unnecessary layout calculations again and again, this slows down performance.
Example: If we need to know an element’s height multiple times, store it in a variable rather than querying it repeatedly.
Avoid inline style changes one-by-one: Avoid modifying inline styles one at a time (which can trigger reflow or repaint), and instead modify styles via class manipulation or batching style changes.
Example: Instead of repeatedly changing inline styles:
// Triggers 2 reflows (slow)
element.style.marginTop = '10px';
element.style.marginBottom = '20px';
Add a class and modify styles in the CSS:
element.classList.add('my-new-class'); // Only one reflow on class change
Script Loading: <script>, defer, and async
When working with JavaScript in HTML, it's important to manage how scripts are loaded and executed to improve performance and avoid blocking the rendering of a web page. The <script> tag plays a crucial role in how resources (scripts) are loaded, and the attributes defer and async help in controlling this behavior.
<script> in <head>
When a regular <script> tag is used, the browser will block the rendering process until the script is fully downloaded and executed.
It is typically placed within the <head> or <body> section of the HTML.
<script defer>
The defer attribute allows the script to download in parallel with HTML parsing. However, it ensures that the script is executed only after the HTML has been completely parsed.
Use defer for dependent scripts
<script async>
The async attribute tells the browser to download the script in parallel and execute it as soon as it is ready, without waiting for the HTML parsing to complete.
This can potentially interrupt DOM parsing if the script is encountered during HTML parsing. The script will be executed as soon as it is fully downloaded, regardless of whether the HTML parsing has completed or not.
Use async for independent scripts
Use case: Independent scripts like analytics that don’t depend on the DOM.
Client-Side Storage Options
Cookies: Small pieces of data (key-value pairs) stored in the browser and sent to the server with every HTTP request.
Useful for tracking sessions, storing authentication tokens, user preferences.
Size Limit: ~4KB per cookie.
Use Case:
Storing session IDs or authentication info.
When we need data accessible by both client and server.
Flags:
Name=Value: Required pair
Domain: Specifies which domain can receive cookie
Path: Specifies URL path for cookie
Expires and Max-Age: Controlling Cookie Expiration
Expires sets an absolute expiration date/time for the cookie in GMT format (e.g., Wed, 06 May 2025 14:46:00 GMT). After this date, the cookie is deleted by the browser.
Max-Age sets the cookie lifetime as a relative number of seconds from when the cookie is set (e.g., max-age=300 means the cookie lives for 5 minutes).
HttpOnly: Restricting JavaScript Access
The HttpOnly flag makes a cookie inaccessible to JavaScript running in the browser (document.cookie cannot read or write it).
This protects sensitive cookies (like session IDs or authentication tokens) from being stolen via cross-site scripting (XSS) attacks.
HttpOnly cookies are still sent automatically with HTTP requests to the server.
Only the server can set or read HttpOnly cookies.
Secure: Sending Cookies Only Over HTTPS
Sent only over HTTPS
This prevents the cookie from being transmitted over unencrypted HTTP, protecting it from man-in-the-middle attacks.
SameSite: Controlling Cross-Site Cookie Sending
The SameSite attribute restricts how cookies are sent with cross-site requests to mitigate cross-site request forgery (CSRF) attacks.
Web Storage API: A simple API to store data in the browser in key-value format.
Not automatically sent to the server (unlike cookies). Includes:
localStorage: Persistent (until manually cleared)
Shared across tabs
~5–10MB
Accessed via localStorage.getItem(), removeItem and setItem().
localStorage.setItem("user", "Manish"); // Set data (persists until manually cleared)
console.log(localStorage.getItem("user")); // Output: "Manish" // Retrieve data
localStorage.removeItem("user"); // Remove specific item
localStorage.clear(); // Clear all localStorage data
sessionStorage: Clears on tab or window close
Isolated per tab – not shared across tabs.
sessionStorage.setItem('draft', 'Hello...'); // Set data (cleared when tab closes)
const draft = sessionStorage.getItem('draft'); // "Hello..." // Retrieve data
sessionStorage.removeItem('draft'); // Remove item
Use: Temporary data like form inputs or navigation state in a single session.
IndexedDB: A NoSQL-style database inside the browser.
Great for storing large, structured data (e.g., to-do apps, offline apps).
Asynchronous and uses transactions and indexing.
Much larger capacity than cookies or localStorage (~hundreds of MBs or more).
Contains object stores
Like a table in SQL, stores key-value records
Accessed via Promises or the indexedDB API.
Example Use Cases: Offline email clients, product catalogs, note-taking apps
Storage Event: Fired in other tabs/windows when localStorage is modified.
Used for multi-tab sync (e.g., user logs out in one tab → logout in all tabs).
Note: The tab making the change does not receive the event.
Web APIs Overview
Web APIs are interfaces provided by the browser or third-party providers that allow JavaScript to interact with browser features or external services.
Built-in Browser APIs: These are provided natively by the browser and don’t require external libraries.
DOM API: Allows JavaScript to manipulate the structure, content, and style of HTML documents. It provides interfaces like Document, Element, and Node to create, modify, or remove elements dynamically.
Fetch API: Allows us to make network requests.
Canvas API: Used to draw graphics via JavaScript.
Geolocation API: Retrieves the user's location (with permission).
Web Storage API: Stores data locally in browser
Web Audio API: Processes and manipulates audio
Third-party APIs: These are not built into the browser, we access them via HTTP requests or SDKs provided by external services.
Google Maps API: For embedding and interacting with maps.
Facebook SDK: For social authentication.
Stripe API: Process payments securely.
Node.js Ecosystem
The Node.js ecosystem consists of tools, libraries, and frameworks that help developers build full-stack, scalable applications using JavaScript on the server side.
Node.js Core
Node.js itself is a runtime built on Google Chrome’s V8 JavaScript engine, enabling JavaScript execution outside the browser on the server side. It includes essential core modules such as:
fs (file system operations)
http (creating web servers)
path (file path utilities)
crypto (cryptographic functions)
Node.js employs a single-threaded event loop architecture combined with a thread pool (via libuv) to handle asynchronous, non-blocking I/O operations efficiently, making it ideal for real-time and networked applications
NPM(Node Package Manager)
Installs third-party libraries
Manages dependencies via package.json
Alternatives: Yarn, pnpm
Express.js: Lightweight, minimalist web framework for Node.js.
Middleware-based architecture (e.g., body-parser, cors, helmet).
Request parsing (body-parser)
Security (helmet, cors)
Authentication (Passport.js, JWT)
Use case: REST API development
Webpack: A module bundler that compiles JavaScript, CSS, images, and more into optimized static assets.
Use Case:
Bundling: Combines JS/CSS/assets into optimized files.
Code Splitting: Supports lazy loading to improve performance.
Tree Shaking: Removes unused code to reduce bundle size.
Hot Module Replacement (HMR) – Updates modules without full page reload (improves dev experience).
Reduces network requests and improves performance.
Common in React/Vue projects.
Alternatives: Vite, Rollup, Parcel.
Transpiling & Babel
Not all browsers support modern features like async/await, let/const, etc.
Babel converts ES6+ → older JS
Converts modern JavaScript (ES6+) to backward-compatible JavaScript for older browsers/environments.
e.g., arrow functions → regular functions, const → var.
Browser vs Node.js
Feature
Browser
Node.js
Purpose
Client-side UI
Server-side apps
Global Object
window
global
File Access
No
Yes (fs module)
DOM Access
Yes
No
Modules
ES Modules
CommonJS & ES Modules
APIs
Web APIs (fetch, DOM)
Node APIs (fs, http)
Use Cases
UI, animations
Backend, APIs, tools
Introduction to ReactJS
React is a JavaScript library developed by Facebook (now Meta) for building interactive and efficient UIs. It emphasizes:
Component-based architecture: Break the UI into small, independent, reusable components.
Benefits:
Reusability
Maintainability
Testability
Clear separation of concerns
Declarative programming style: You describe what you want to see on the screen. React abstracts DOM manipulations for a cleaner and more expressive syntax.
Imperative (Vanilla JS):
const div = document.createElement("div"); div.id = "welcome"; div.innerText = "Hello World"; document.getElementById("root").appendChild(div);
Declarative (React):
const Welcome = () => ( <div id="welcome"> <h1>Hello World</h1> </div> );
Efficient updates via Virtual DOM: Efficient and fast UI updates.
Unidirectional data flow: Makes apps predictable and easier to debug.
Key Concepts:
Components: Building blocks of a React app.
Functional components.
Defined as JavaScript functions.
Use Hooks (like useState, useEffect) for managing logic and state.
Preferred in modern React development.
Class components(Legacy)
Use this.state and lifecycle methods.
Still valid but being replaced by functional components.
Reusable: Write once, use many times.
Self-contained: Handle their own structure, behavior, and state. Each component encapsulates:
UI – What it renders (via JSX)
Behavior (how it responds to interactions)
State management (what data it tracks)
Lifecycle (when it appears, updates, and disappears)
Component Nesting & Communication: Components can be nested inside each other to build complex UIs, and they communicate via props (properties passed from parent to child), which are read-only and ensure predictable, one-way data flow
Virtual DOM: React doesn't manipulate the real DOM directly. It uses:
Virtual DOM – A lightweight JavaScript representation of the real DOM.
React updates only the changed parts, not the entire UI.
Results in better performance.
Batching updates.
Minimizes expensive reflows and repaints.
Diffing Algorithm – Compares old and new Virtual DOMs.
Reconciliation – Updates only the changed parts in the actual DOM.
One-way Data Binding: Data flows unidirectionally (from parent to child).
Achieved via props.
Prevents unexpected mutations and side-effects.
State and Props
State: State is local to a component and represents data that can change over time, typically managed using hooks like useState in functional components or this.state in class components. State updates trigger re-rendering of the component to reflect the new data
A way for components to remember and react to changes.
Old way: Class component with this.state
New way: Functional component with useState hook
const [count, setCount] = useState(0);
Props: Props are inputs to components, passed from parent to child, and are immutable within the child.
Props are read-only.
Passed like HTML attributes.
<Course name="React" credits="3" />
ReactDOM: Used to render React components into the actual DOM.
Example: ReactDOM.render(<App />, document.getElementById('root'));
From CRA to Vite, Next.js, Remix:
CRA (Create React App): Previously standard for bootstrapping React apps.
Now deprecated.
Modern Alternatives:
Vite – Blazing fast dev server, hot reloading.
Next.js – SSR + routing + API support.
Remix – Full-stack React framework.
Parcel – Zero-config, fast bundler.
JSX (JavaScript XML): JSX is a syntax extension that allows us to write HTML-like code directly inside JavaScript.
It’s transpiled to React.createElement() calls.
Example: const element = <h1>Hello, world!</h1>;
class becomes className
for becomes htmlFor
Inline styles use object syntax:
<div style={{ color: 'red' }}>Hi</div>
Rendering Lists with .map(): Add a unique key prop to help React identify which items changed.
const courses = ["React", "Node", "GraphQL"]; const listItems = courses.map(course => <li key={course}>{course}</li>);
React Fragments: Allows returning multiple elements without adding extra nodes.
<React.Fragment> <h1>Title</h1> <p>Paragraph</p> </React.Fragment>
Conditional Rendering: Techniques: if/else, Ternary condition ? A : B, && short circuit
{isLoggedIn && <LogoutButton />}
Context API: Solves prop drilling by sharing data globally.
const MyContext = React.createContext(); <MyContext.Provider value={value}> <Component /> </MyContext.Provider> // Inside child: const context = useContext(MyContext);
Routing in React: React Router: Library for handling SPA routing. Components:
<BrowserRouter>: standard HTML5 routing
<Routes>: container for routes
<Route>: Define individual routes. Define which UI to render for a given path
<Link>: client-side navigation
<Outlet>: Nesting child components
<Navigate>: Redirect programmatically
Example:
<BrowserRouter> <Routes> <Route path="/" element={<Home />} /> <Route path="/about" element={<About />} /> </Routes> </BrowserRouter>
Redux – Centralized State Management: In large apps, managing component-to-component state gets complex. Redux offers:
Centralized store
Predictable updates
Easier debugging and testing
Redux Concepts:
Store: Single source of truth
const store = createStore(reducer);
Actions: Describe state changes
const action = { type: "INCREMENT" };
Reducers: Pure functions to handle actions
function reducer(state = 0, action) { switch (action.type) { case "INCREMENT": return state + 1; default: return state; } }
Dispatch: Send action to reducer
store.dispatch({ type: "INCREMENT" });
Redux Best Practices:
Use combineReducers() for modular state slices.
Never mutate the state directly.
Use Redux middleware (e.g., redux-thunk, redux-saga) for async logic.
Use useSelector() and useDispatch() with React-Redux hooks.
React Component Lifecycle
Lifecycle in Class Components:
Mounting Phase(Initial render): This phase occurs when a component is created and inserted into the DOM for the first time. It involves these key lifecycle methods:
constructor(): Initializes state and binds event handlers. It is the first method called but should avoid side effects like API calls.
static getDerivedStateFromProps(props, state): Invoked right before rendering, both on mount and update, to update state based on props.
render(): Returns the JSX to render the UI.
componentDidMount(): Called after the component is mounted in the DOM. Ideal for side effects like fetching data, setting up subscriptions.
Updating (on props/state change): Triggered when component props or state change, causing a re-render. The lifecycle methods here include:
getDerivedStateFromProps: Update state from props.
shouldComponentUpdate: Determines whether the component should re-render. Returning false skips rendering for performance optimization.
render(): Re-renders the component with new state/props.
getSnapshotBeforeUpdate: Captures some information (e.g., scroll position) before the DOM is updated.
componentDidUpdate: Perform actions after update. Useful for operations like network requests based on prop or state changes.
Unmounting: Occurs when the component is removed from the DOM. Method:
componentWillUnmount() → Used for cleanup tasks such as clearing timers, canceling network requests, or removing event listeners.
Error Handling: To catch errors during rendering or lifecycle methods:
getDerivedStateFromError: Updates state to display a fallback UI.
componentDidCatch: Logs error information.
Functional Components Lifecycle (Hooks)
In functional components, React Hooks handle lifecycle events that were previously managed by lifecycle methods in class components. The key hook here is useEffect(), which allows us to run side effects in function components.
useEffect Hook: Runs side effects after rendering:
useEffect(() => { console.log("Component mounted or updated"); }, []);
[] runs once (like componentDidMount)
No array = every render
[deps] = re-run on dependency change
Lifecycle Method (Class)
Equivalent in Functional Components
Explanation
componentDidMount
useEffect(() => {}, [])
The empty array ([]) as the dependency means the effect will only run once when the component is mounted
componentDidUpdate
useEffect(() => {}, [state/prop])
Re-render when props/state change
componentWillUnmount
useEffect(() => { return () => {} }, [])
The return statement inside useEffect is a cleanup function that runs when the component is about to unmount
Example: Functional Component with Lifecycle:
import React, { useState, useEffect } from 'react'; function Counter() { const [count, setCount] = useState(0); useEffect(() => { console.log("Component mounted or updated"); return () => { console.log("Component unmounted"); }; }, [count]); return ( <div> <p>We clicked {count} times</p> <button onClick={() => setCount(count + 1)}>Click me</button> </div> ); }
Last updated