Full-Stack Interview
Preparation Notes
React · [Link] · Database · HTML/CSS · JavaScript · Dev Concepts
Comprehensive notes, code snippets & interview Q&A;
[Link] [Link] Database HTML/CSS JavaScript Dev Concepts
■ [Link]
Components • Hooks • State • Routing • Virtual DOM
1.1 Components — Functional vs Class
Modern React uses functional components almost exclusively. Class components are legacy but still appear in
older codebases and some interviews.
Aspect Functional Component Class Component
Definition JS function returning JSX ES6 class extending [Link]
State useState() hook [Link] & [Link]()
Lifecycle useEffect() hook componentDidMount / Update / Unmount
Performance Slightly lighter Heavier due to class overhead
Usage today ■ Preferred Legacy / rarely used
// Functional Component
const Counter = () => {
const [count, setCount] = [Link](0);
return <button onClick={() => setCount(c => c+1)}>{count}</button>;
};
1.2 Core Hooks
useState
Adds local state to a functional component.
const [val, setVal] = useState(initial);
useEffect
Run side-effects (fetch, subscriptions, timers). Runs after render.
useEffect(() => { /* effect */ return () => { /* cleanup */ }; }, [deps]);
useRef
Mutable ref that doesn't trigger re-render. Also used to access DOM nodes.
const inputRef = useRef(null); [Link]();
useContext
Consume a React context without prop drilling.
const theme = useContext(ThemeContext);
useMemo
Memoize expensive computed value.
const sorted = useMemo(() => [Link](), [items]);
useCallback
Memoize a function reference to avoid child re-renders.
const handleClick = useCallback(() => doSomething(id), [id]);
1.3 Props, State & Lifting State Up
Props are read-only inputs passed from parent to child. State is mutable data owned by a component. When
sibling components need to share state, lift it up to their nearest common ancestor.
// Lifting state example
const Parent = () => {
const [value, setValue] = useState('');
return (
<>
<InputChild value={value} onChange={setValue} />
<DisplayChild value={value} />
</>
);
};
■ Tip: Always keep state as close to where it's needed as possible. Only lift when two components need the same
data.
1.4 React Router Basics
import { BrowserRouter, Routes, Route, Link, useParams } from 'react-router-dom';
<BrowserRouter>
<Routes>
<Route path='/' element={<Home />} />
<Route path='/user/:id' element={<User />} />
<Route path='*' element={<NotFound />} />
</Routes>
</BrowserRouter>
// Inside User component
const { id } = useParams();
1.5 Virtual DOM
React maintains an in-memory representation of the real DOM called the Virtual DOM. On every state change,
React creates a new VDOM tree, diffs it against the previous one (reconciliation), and applies only the minimal set
of real DOM mutations — making UI updates fast.
■ Tip: Key reconciliation rule: always provide a unique key prop when rendering lists so React can efficiently
identify which items changed.
Interview Q&A; — React
Q: What is the difference between controlled and uncontrolled components?
A: Controlled: form data is driven by React state (value + onChange). Uncontrolled: form data is handled by
the DOM itself via ref. Controlled is preferred for validation and consistency.
Q: When would you use useCallback vs useMemo?
A: useMemo caches a computed value; useCallback caches a function reference. Use useCallback when
passing callbacks to optimised child components ([Link]) to prevent unnecessary re-renders.
Q: What is [Link] and when should you use it?
A: [Link] is a HOC that skips re-rendering a functional component if its props haven't changed. Use it
for expensive components that receive the same props frequently.
Q: Explain the useEffect dependency array.
A: [] = run once on mount; [a,b] = run when a or b changes; omitted = run after every render. Always include all
reactive values used inside the effect.
■ [Link]
Pages Router · App Router · SSR · SSG · CSR · API Routes
2.1 Pages Router vs App Router
Feature Pages Router (/pages) App Router (/app)
Introduced [Link] v1 [Link] 13+
Data fetching getServerSideProps / getStaticProps async Server Components / fetch()
Layouts Custom _app.js [Link] files (nested)
Server Components Not supported ■ Default
Streaming Limited ■ Built-in with Suspense
Status Stable / legacy ■ Recommended
2.2 Rendering Strategies
SSR — Server-Side Rendering
Page HTML is generated on each request on the server. Data is always fresh.
Use for: personalised dashboards, real-time data (stock prices, news feeds).
SSG — Static Site Generation
HTML is generated at build time. Served from CDN — blazing fast.
Use for: blogs, docs, marketing pages where data rarely changes.
CSR — Client-Side Rendering
Browser fetches a minimal HTML shell; JS fetches & renders data on the client.
Use for: user-specific data behind a login (cart, profile) or highly interactive sections.
ISR — Incremental Static Regeneration
SSG pages re-generated in background at a given interval without a full rebuild.
Use for: e-commerce product pages, content that updates occasionally.
2.3 Data Fetching — Pages Router
// getServerSideProps — runs on every request
export async function getServerSideProps(context) {
const data = await fetch(`/api/posts/${[Link]}`).then(r => [Link]());
return { props: { data } };
}
// getStaticProps — runs at build time
export async function getStaticProps() {
const posts = await fetchAllPosts();
return { props: { posts }, revalidate: 60 }; // ISR: re-gen every 60s
}
// getStaticPaths — required with dynamic SSG routes
export async function getStaticPaths() {
const ids = await fetchPostIds();
return { paths: [Link](id => ({ params: { id } })), fallback: 'blocking' };
}
2.4 Data Fetching — App Router
// Server Component (default in /app) — just use async/await
export default async function Page({ params }) {
const data = await fetch(`[Link]
{ next: { revalidate: 60 } } // ISR
).then(r => [Link]());
return <main>{[Link]}</main>;
}
2.5 API Routes
// pages/api/[Link] (Pages Router)
export default function handler(req, res) {
if ([Link] === 'GET') return [Link](200).json({ msg: 'Hello' });
[Link](405).end();
}
// app/api/hello/[Link] (App Router)
export async function GET(request) {
return [Link]({ msg: 'Hello' });
}
2.6 Image Optimization & Link
import Image from 'next/image';
import Link from 'next/link';
// next/image: lazy loading, WebP conversion, responsive sizing built-in
<Image src='/[Link]' alt='Hero' width={800} height={400} priority />
// next/link: client-side navigation with prefetching
<Link href='/about'>About</Link>
Interview Q&A; — [Link]
Q: What's the difference between SSR and SSG?
A: SSR generates HTML per request (always fresh data, slower TTFB). SSG generates HTML at build time
(super fast, served from CDN, data may be stale). ISR bridges the gap by re-generating static pages
periodically.
Q: How does the App Router differ from Pages Router in terms of layouts?
A: App Router uses nested [Link] files so each route segment can define its own layout that persists across
child routes. Pages Router requires wrapping pages manually in _app.js or custom HOCs.
Q: What is a Server Component?
A: A React Server Component (default in /app) renders only on the server. It can directly access databases,
file systems, and secrets without shipping any JS to the browser — reducing bundle size significantly.
■ Database Basics
SQL vs NoSQL · CRUD · Joins · MongoDB · Indexing
3.1 SQL vs NoSQL
Aspect SQL (Relational) NoSQL (Non-Relational)
Data model Tables with rows & columns Documents, KV, graph, column-family
Schema Fixed, predefined Flexible / schema-less
Scaling Vertical (scale up) Horizontal (scale out)
ACID ■ Full ACID compliance Usually eventual consistency
Query lang SQL Varies (MQL, CQL, Cypher…)
Best for Complex queries, financial data High-volume, unstructured, fast writes
Examples MySQL, PostgreSQL, SQLite MongoDB, Redis, Cassandra, DynamoDB
3.2 Basic CRUD — SQL & MongoDB
-- SQL CRUD
INSERT INTO users (name, email) VALUES ('Alice', 'a@[Link]');
SELECT * FROM users WHERE id = 1;
UPDATE users SET email = 'b@[Link]' WHERE id = 1;
DELETE FROM users WHERE id = 1;
// MongoDB CRUD (Mongoose)
await [Link]({ name: 'Alice', email: 'a@[Link]' });
await [Link](id);
await [Link](id, { email: 'b@[Link]' }, { new: true });
await [Link](id);
3.3 SQL Joins
• INNER JOIN — Returns rows that have matching values in BOTH tables. Most common join.
• LEFT JOIN — Returns ALL rows from the left table + matched rows from right. Unmatched right rows are
NULL.
• RIGHT JOIN — Opposite of LEFT JOIN. All rows from right, matched from left.
• FULL OUTER JOIN — Returns all rows when there's a match in either table.
-- INNER JOIN example
SELECT [Link], [Link]
FROM orders
INNER JOIN users ON orders.user_id = [Link];
-- LEFT JOIN (include users with no orders)
SELECT [Link], [Link]
FROM users
LEFT JOIN orders ON [Link] = orders.user_id;
3.4 MongoDB Basics
// Schema definition with Mongoose
const userSchema = new [Link]({
name: { type: String, required: true },
email: { type: String, unique: true },
age: Number,
createdAt: { type: Date, default: [Link] }
});
const User = [Link]('User', userSchema);
// Querying
await [Link]({ age: { $gte: 18 } }).sort({ name: 1 }).limit(10);
// Aggregation
await [Link]([
{ $match: { age: { $gte: 18 } } },
{ $group: { _id: '$city', count: { $sum: 1 } } },
]);
3.5 Indexing
An index is a data structure (usually B-Tree) that speeds up read queries at the cost of slightly slower writes and
extra storage. Without an index, the DB performs a full table scan (O(n)).
• Primary index: automatically created on the primary key.
• Composite index: index on multiple columns — order matters (leftmost prefix rule).
• Unique index: enforces uniqueness, e.g. on email fields.
• Avoid over-indexing — every index slows down INSERT/UPDATE/DELETE operations.
-- SQL index
CREATE INDEX idx_email ON users(email);
// MongoDB index
await [Link]({ email: 1 }, { unique: true });
await [Link]({ age: 1, city: 1 }); // compound
Interview Q&A; — Database
Q: When would you choose MongoDB over PostgreSQL?
A: MongoDB when: schema is flexible/evolving, storing hierarchical or JSON-like data, need horizontal scaling,
rapid prototyping. PostgreSQL when: complex relationships, ACID transactions, financial data, reporting
queries.
Q: What is N+1 query problem?
A: Fetching 1 list + N additional queries for each item (e.g., get 100 posts then 100 separate author queries).
Fix with JOINs in SQL or populate() / aggregation in MongoDB, or DataLoader batching in GraphQL.
Q: Explain database normalization.
A: Process of structuring a DB to reduce redundancy. 1NF: atomic columns. 2NF: remove partial
dependencies. 3NF: remove transitive dependencies. Normalised DBs save storage but may need more
JOINs.
80 HTML / CSS
Semantic HTML5 · Flexbox · Grid · Responsive · Variables · A11y
4.1 Semantic HTML5 Tags
Tag Purpose
<header> Site/section header — logo, nav
<nav> Navigation links block
<main> Primary content of page (one per page)
<article> Self-contained content (blog post, card)
<section> Thematic grouping of content
<aside> Sidebar / tangentially related content
<footer> Footer — copyright, links
<figure> / <figcaption> Image + caption pair
<time> Machine-readable date/time
■ Tip: Semantic HTML improves SEO, accessibility, and maintainability. Avoid div-soup!
4.2 Flexbox
.container {
display: flex;
flex-direction: row; /* row | column */
justify-content: center; /* main axis: flex-start | center | space-between |
space-around */
align-items: center; /* cross axis: flex-start | center | stretch | baseline */
flex-wrap: wrap; /* allow wrapping */
gap: 16px;
}
.item { flex: 1; } /* grow to fill available space */
4.3 CSS Grid
.grid {
display: grid;
grid-template-columns: repeat(3, 1fr); /* 3 equal columns */
grid-template-rows: auto;
gap: 16px;
}
/* Responsive grid without media queries */
.auto-grid {
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
}
/* Span items */
.wide-item { grid-column: span 2; }
4.4 Responsive Design & Media Queries
/* Mobile-first approach */
.card { padding: 12px; font-size: 14px; }
@media (min-width: 768px) { /* Tablet */
.card { padding: 20px; font-size: 16px; }
}
@media (min-width: 1024px) { /* Desktop */
.card { padding: 32px; font-size: 18px; }
}
/* Prefer logical properties for i18n */
.btn { padding-inline: 1rem; margin-block: 0.5rem; }
■ Tip: Always design mobile-first. Add complexity as screen size grows, not the reverse.
4.5 CSS Variables & Specificity
:root {
--color-primary: #7c3aed;
--spacing-md: 16px;
--radius: 8px;
}
.btn { background: var(--color-primary); border-radius: var(--radius); }
Specificity order (highest → lowest):
• Inline styles (1,0,0,0)
• IDs (0,1,0,0)
• Classes / attributes / pseudo-classes (0,0,1,0)
• Elements / pseudo-elements (0,0,0,1)
• !important overrides everything — avoid it.
4.6 Accessibility Basics
• Use semantic tags so screen readers understand structure.
• Every image needs a descriptive alt attribute (empty alt='' for decorative images).
• Ensure color contrast ≥ 4.5:1 for normal text (WCAG AA standard).
• All interactive elements must be keyboard-navigable (Tab, Enter, Space, Arrow keys).
• Use aria-label / aria-describedby when native semantics are insufficient.
• Use styles — never remove outline without a replacement.
Interview Q&A; — HTML/CSS
Q: Flexbox vs Grid — when to use which?
A: Flexbox is 1-dimensional (row OR column) — ideal for nav bars, card rows, centering. Grid is 2-dimensional
(rows AND columns) — ideal for page layouts, image galleries, complex grids.
Q: What is the box model?
A: Every element is a rectangular box: content → padding → border → margin. box-sizing: border-box makes
width/height include padding and border, which is far more intuitive and is now the standard.
Q: What is CSS specificity and how do you resolve conflicts?
A: Specificity determines which CSS rule wins when multiple rules target the same element. Calculate scores:
inline > ID > class/attribute > element. Use lower-specificity selectors and BEM naming to avoid conflicts.
Avoid !important.
JS JavaScript
ES6+ · Promises · Async/Await · DOM · Events · Closures · Fetch
5.1 ES6+ Must-Know Features
// Arrow functions (implicit return for single expressions)
const add = (a, b) => a + b;
// Destructuring
const { name, age = 18 } = user; // object
const [first, ...rest] = items; // array
// Spread / Rest
const merged = { ...defaults, ...overrides };
const sum = (...nums) => [Link]((a, b) => a + b, 0);
// Template literals
const msg = `Hello, ${name}! You are ${age} years old.`;
// Optional chaining & nullish coalescing
const city = user?.address?.city ?? 'Unknown';
// Modules
export const PI = 3.14; // named export
export default function App() {} // default export
import App, { PI } from './app'; // import
5.2 Promises & Async/Await
A Promise represents a value that may be available now, in the future, or never. It has three states: pending,
fulfilled, rejected.
// Promise chain
fetch('/api/data')
.then(res => [Link]())
.then(data => [Link](data))
.catch(err => [Link](err));
// Async/Await (syntactic sugar over Promises)
const getData = async () => {
try {
const res = await fetch('/api/data');
const data = await [Link]();
return data;
} catch (err) {
[Link](err);
}
};
// Parallel requests
const [users, posts] = await [Link]([fetchUsers(), fetchPosts()]);
5.3 DOM Manipulation
// Selecting elements
const el = [Link]('.card'); // first match
const all = [Link]('li'); // NodeList
// Modifying
[Link] = 'Hello';
[Link]('active'); [Link]('open');
[Link]('aria-label', 'Close');
// Creating & inserting
const div = [Link]('div');
[Link] = '<p>Hello</p>';
[Link](div);
[Link]('beforeend', '<span>!</span>');
5.4 Event Handling & Closures
// Event listener
[Link]('#btn').addEventListener('click', handleClick);
// Event delegation (attach once to parent, filter by target)
[Link]('#list').addEventListener('click', (e) => {
if ([Link]('li')) [Link]([Link]);
});
// Closure example — counter factory
function makeCounter() {
let count = 0; // private via closure
return () => ++count;
}
const counter = makeCounter();
counter(); // 1 counter(); // 2
■ Tip: Closures let inner functions access outer function variables even after the outer function has returned.
Useful for private state, currying, and memoisation.
5.5 Fetch API & Axios
// Fetch (built-in)
const res = await fetch('/api/items', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: [Link]({ name: 'Alice' }),
});
const data = await [Link]();
// Axios (library — handles JSON automatically, better error handling)
import axios from 'axios';
const { data } = await [Link]('/api/items', { name: 'Alice' });
// Interceptor for auth headers
[Link]['Authorization'] = `Bearer ${token}`;
Interview Q&A; — JavaScript
Q: Explain the event loop.
A: JS is single-threaded. The call stack executes synchronous code. Async callbacks (from setTimeout, fetch,
DOM events) are queued in the task queue or microtask queue (Promises). The event loop picks tasks when
the call stack is empty. Microtasks (Promises) run before macrotasks (setTimeout).
Q: var vs let vs const?
A: var: function-scoped, hoisted, can be redeclared. let: block-scoped, not hoisted (TDZ), can be reassigned.
const: block-scoped, must be initialised, cannot be reassigned (but object properties can mutate). Prefer const
> let > never var.
Q: What is prototype chain?
A: Every JS object has an internal [[Prototype]] link. Property lookup traverses this chain until found or null is
reached. ES6 classes are syntactic sugar over prototype-based inheritance.
Q: Difference between == and ===?
A: == performs type coercion before comparison. === compares without coercion (strict equality). Always use
=== to avoid surprising bugs like 0 == false being true.
■ Dev Concepts
Git · REST APIs · Performance · UI/UX · Component Reusability
6.1 Git Basics
Command What it does
git init Initialise a new local repository
git clone <url> Clone a remote repository
git add . Stage all changes
git commit -m 'msg' Create a commit with a message
git push origin main Push commits to remote
git pull Fetch + merge remote changes
git branch feature Create a new branch
git checkout -b feat Create and switch to new branch
git merge feature Merge branch into current
git rebase main Reapply commits on top of main (cleaner history)
git stash Temporarily shelve uncommitted changes
git log --oneline Compact commit history
Pull Request (PR) Workflow:
• Create feature branch from main/dev.
• Make commits — small, atomic, descriptive messages (Conventional Commits: feat:, fix:, chore:).
• Push branch and open a Pull Request on GitHub/GitLab.
• Code review — address feedback, push new commits.
• Merge after approval (squash merge keeps history clean).
• Delete feature branch after merge.
6.2 REST APIs
HTTP Method CRUD Example URL Response
Operation
GET Read GET /api/users 200 + array
GET Read GET /api/users/:id 200 + object or 404
POST Create POST /api/users 201 + created object
PUT Replace PUT /api/users/:id 200 + updated or 204
HTTP Method CRUD Example URL Response
Operation
PATCH Update PATCH /api/users/:id 200 + updated
DELETE Delete DELETE /api/users/:id 204 No Content
REST Principles:
• Stateless — each request contains all info needed; no session on server.
• Resource-based URLs — nouns, not verbs: /users not /getUsers.
• Use proper HTTP status codes: 200 OK, 201 Created, 400 Bad Request, 401 Unauthorized, 403 Forbidden,
404 Not Found, 500 Server Error.
• Version your API: /api/v1/users.
6.3 Performance Optimization
JavaScript
• Code split with dynamic import() — load only what's needed.
• Debounce/throttle scroll and resize listeners.
• Use Web Workers for CPU-intensive tasks.
React
• [Link] + useCallback/useMemo to prevent unnecessary re-renders.
• Virtualise long lists (react-window / react-virtual).
• Lazy load components with [Link] + Suspense.
Network
• Enable HTTP/2, gzip/Brotli compression.
• CDN for static assets — reduce latency globally.
• Prefetch / preconnect critical resources in <head>.
Images
• Use modern formats: WebP / AVIF.
• Serve responsive images with srcset.
• Lazy load below-the-fold images (loading='lazy').
■ Tip: Measure first! Use Chrome DevTools → Lighthouse to find actual bottlenecks. Core Web Vitals: LCP <
2.5s, FID < 100ms, CLS < 0.1
6.4 UI/UX Feasibility
• Evaluate design mockups for technical complexity before committing to estimates.
• Smooth animations: prefer CSS transforms/opacity (GPU-accelerated) over animating layout properties.
• Progressive disclosure: show minimal UI initially, reveal complexity on demand.
• Loading states: always design skeleton screens or spinners for async operations.
• Error states: every data-fetching component needs an error fallback.
• Mobile touch targets must be ≥ 44×44px (Apple HIG / Material guidelines).
6.5 Component Reusability
Build components that are single-responsibility, composable, and configurable via props. Follow these
patterns:
// ■ Reusable Button with variants
const Button = ({ variant = 'primary', size = 'md', children, ...props }) => (
<button className={`btn btn-${variant} btn-${size}`} {...props}>
{children}
</button>
);
// ■ Compound components (Menu pattern)
<Menu>
<[Link]>Open</[Link]>
<[Link]>
<[Link]>Edit</[Link]>
<[Link]>Delete</[Link]>
</[Link]>
</Menu>
// ■ Custom hook to extract logic
const useFetch = (url) => {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
fetch(url).then(r => [Link]()).then(d => { setData(d); setLoading(false); });
}, [url]);
return { data, loading };
};
Interview Q&A; — Dev Concepts
Q: What is the difference between git merge and git rebase?
A: Merge preserves full history with a merge commit (non-destructive, shows branching). Rebase rewrites
commit history onto another branch tip (linear history, cleaner log). Use rebase for feature branches before
PR; use merge for integrating into main.
Q: What are Core Web Vitals?
A: Google's user-experience metrics: LCP (Largest Contentful Paint) = loading performance < 2.5s; FID/INP =
interactivity < 100ms; CLS (Cumulative Layout Shift) = visual stability < 0.1. They directly affect SEO ranking.
Q: How would you optimise a slow React app?
A: Profile with React DevTools to find slow renders. Memoize with [Link]/useMemo/useCallback.
Code-split large routes with [Link]. Virtualize long lists. Move state down or use context wisely. Check for
unnecessary re-renders and side-effect loops in useEffect.
Q: What is CORS and how do you handle it?
A: Cross-Origin Resource Sharing — browser security policy that blocks requests to different origins. Fixed
server-side by setting Access-Control-Allow-Origin headers. In [Link] API routes, set headers in the handler
or use a middleware. In development, proxy via [Link] rewrites.
■ Quick Reference Cheat Sheet
Key concepts at a glance — print this page!
React Hooks useState, useEffect, useRef, useContext, useMemo, useCallback
React Router BrowserRouter > Routes > Route | Link, useNavigate, useParams
[Link] Data SSR=getServerSideProps SSG=getStaticProps ISR=revalidate CSR=useEffect+fetch
SQL Joins INNER (both match) | LEFT (all left) | RIGHT (all right) | FULL OUTER (all)
HTTP Methods GET=read POST=create PUT=replace PATCH=update DELETE=remove
HTTP Codes 200 OK | 201 Created | 204 No Content | 400 Bad Request | 401 Unauth | 403 Forbidden | 404 Not
Found | 500 Server Error
CSS Flex flex-direction | justify-content (main) | align-items (cross) | flex-wrap | gap
CSS Grid grid-template-columns | repeat(auto-fit, minmax()) | gap | grid-column: span N
Specificity inline(1000) > ID(100) > class/attr(10) > element(1)
JS ES6+ const/let | arrow fn | destructuring | spread | optional chaining | nullish coalescing
Promises pending → fulfilled/rejected | .then().catch() | async/await | [Link]([])
Event Loop Call Stack → Microtask Queue (Promises) → Macro Task Queue (setTimeout, setInterval)
Git Flow main ← dev ← feature branches | commit → push → PR → review → merge
Closures Inner function retains access to outer scope variables even after outer fn returns
Performance LCP<2.5s | CLS<0.1 | INP<100ms | lazy load | code split | CDN | memoize
A11y semantic HTML | alt text | contrast ≥4.5:1 | keyboard nav | ARIA labels
Good luck with your interview! Remember: clarity of thought > memorisation. Explain your reasoning, ask clarifying
questions, and think out loud.