Episode 2 — React Frontend Architecture NextJS / 2.1 — Introduction to React
Interview Questions: Introduction to React
These questions simulate real interview scenarios. Practice explaining concepts clearly and concisely — interviewers care about how you think, not just what you know.
How to Use This Material
- Read the question and formulate your answer before reading the model answer.
- Time yourself — aim for 1-2 minute verbal answers (concise but complete).
- Practice out loud — saying it builds fluency that reading silently does not.
- Understand the "Why interviewers ask this" section — it tells you what they're really evaluating.
- Don't memorize — internalize the concepts so you can explain them in your own words.
Beginner (Q1–Q6)
Q1. What is React and why would you use it?
Why interviewers ask this: They want to see if you understand React's purpose beyond "it's popular." They're checking whether you grasp the actual problems it solves vs. alternatives.
Model answer: React is a JavaScript library for building user interfaces, created by Facebook in 2013. It solves the core problem of keeping the UI in sync with application data — something that becomes extremely difficult with vanilla JavaScript as applications grow.
The key reasons to use React are:
First, it uses a declarative model — you describe what the UI should look like for any given state, and React figures out how to update the DOM efficiently. This eliminates an entire category of bugs where the DOM gets out of sync with your data.
Second, it's component-based — you break the UI into independent, reusable pieces. This makes code easier to understand, test, and maintain. A team of 10 developers can work on different components without stepping on each other's toes.
Third, the Virtual DOM and reconciliation algorithm mean you get good performance without manually optimizing DOM operations. You write simple, readable code and React handles the optimization.
I'd choose React for interactive, data-heavy applications — dashboards, social platforms, e-commerce sites. For a simple static marketing page, something lighter might be more appropriate.
Q2. What is the Virtual DOM and how does it work?
Why interviewers ask this: This is a fundamentals check. They want to know if you understand React's rendering mechanism beyond a surface-level buzzword.
Model answer: The Virtual DOM is a lightweight JavaScript representation of the actual DOM. It's essentially a tree of plain JavaScript objects that mirrors the structure of your real DOM elements.
Here's how it works in three steps:
When a component's state or props change, React creates a new Virtual DOM tree representing what the UI should look like now. Then React diffs the new tree against the previous one — this is called reconciliation. It identifies the minimal set of changes needed. Finally, React batches those changes and applies them to the real DOM in a single operation.
The key insight is that JavaScript operations on plain objects (comparing, creating) are extremely fast — orders of magnitude faster than DOM operations that trigger browser layout, paint, and composite cycles. So by doing the diffing work in JavaScript land first, React minimizes the expensive real DOM operations.
One nuance worth mentioning: the Virtual DOM isn't inherently faster than hand-optimized direct DOM manipulation. What it gives you is consistently good performance without manual optimization. You write simple, declarative code and get performance that's good enough for the vast majority of applications.
Q3. What is JSX?
Why interviewers ask this: They're testing whether you understand that JSX is syntactic sugar, not a template language. They also want to see if you know what it compiles to.
Model answer: JSX is a syntax extension for JavaScript that lets you write HTML-like code inside your JavaScript files. It looks like HTML but it's not — it's JavaScript in disguise.
When you write <h1 className="title">Hello</h1>, Babel (or another transpiler) compiles it to React.createElement('h1', { className: 'title' }, 'Hello'). So JSX is syntactic sugar over React.createElement calls.
This matters for a few reasons: You use className instead of class because it's JavaScript underneath and class is a reserved keyword. You use curly braces {} to embed JavaScript expressions. Style attributes take objects, not strings. And every JSX expression must have a single root element because a function can only return one value.
JSX isn't required to use React — you could write React.createElement calls directly — but nobody does because JSX is dramatically more readable. It's the "declarative" part of React's declarative model — you're literally describing the UI structure.
Q4. What is the difference between a SPA and a traditional multi-page application?
Why interviewers ask this: They want to understand your grasp of web architecture fundamentals and trade-offs.
Model answer: In a traditional multi-page application, every navigation action sends a request to the server, which responds with a complete HTML page. The browser discards the current page and renders the new one from scratch. This causes a full page reload — you see a white flash, lose client-side state, and the experience feels discontinuous.
In a Single Page Application, the server sends one HTML page with a JavaScript bundle on the initial load. After that, navigation happens entirely in the browser. When you click a link, JavaScript intercepts it, fetches any new data via API calls, and updates the DOM — no page reload. The URL changes via the History API, but the page itself never reloads.
The trade-offs are:
SPAs give a smoother user experience — transitions feel instant, you can maintain state (like form inputs or scroll position) across navigations, and the application feels more like a desktop app.
But SPAs have challenges: initial load is heavier (you're downloading the entire application upfront), SEO is harder (search engines may not execute JavaScript), and the blank page problem means users see nothing until JavaScript loads and executes.
Modern solutions like Next.js blur this line — they offer server-side rendering for the initial load (solving SEO and blank page issues) while still providing SPA-like navigation afterward. This "best of both worlds" approach is becoming the standard.
Q5. Explain the concept of component-based architecture.
Why interviewers ask this: This tests your ability to think about UI design at an architectural level, not just write code.
Model answer: Component-based architecture means building an application by assembling independent, self-contained pieces — each responsible for a specific part of the UI. Instead of thinking about a page as one monolithic HTML document, you think about it as a tree of nested components.
Each component has a clear boundary — it owns its rendering logic, manages its own state (if any), and exposes a clean interface through props. Think of it like Lego bricks: each brick is well-defined, and you build complex structures by composing simple pieces.
For example, a Twitter feed page breaks down into: an App component containing a Sidebar, MainFeed, and TrendingSidebar. The MainFeed contains a ComposeTweet box and a TweetList. Each Tweet contains an Avatar, TweetHeader, TweetContent, and TweetActions. The Avatar component might also be reused in the ComposeTweet box and in follow suggestions.
The key benefits are reusability (Avatar is used in three places), isolation (a bug in TweetActions doesn't affect the Sidebar), testability (test each component independently), and team scalability (one developer can own the Sidebar while another works on the TweetList).
The main skill in React development is knowing how to decompose a design into a component tree — deciding where to draw the boundaries, what data each component needs, and how they communicate.
Q6. What is Vite and why is it used instead of Create React App?
Why interviewers ask this: They're checking if you're current with the ecosystem and understand build tooling concepts.
Model answer: Vite is a build tool and development server for modern frontend projects. It replaced Create React App as the recommended way to start new React projects.
The main reason is speed. CRA uses Webpack, which bundles your entire application before the dev server can start. For a large project, this can take 30-60 seconds. Vite uses a fundamentally different approach: it serves your source files directly as ES modules during development, transforming files on-demand only when the browser requests them. This means the dev server starts in under a second regardless of project size.
Vite also provides instant Hot Module Replacement — when you change a file, only that module is replaced, preserving application state. With Webpack-based setups, HMR can take several seconds in large projects.
For production builds, Vite uses Rollup under the hood, which produces highly optimized output with tree shaking, code splitting, and minification.
CRA has been effectively deprecated — its last major release was years ago, and the React team no longer recommends it. Vite, along with Next.js, is now the standard starting point.
Intermediate (Q7–Q12)
Q7. Explain declarative vs imperative programming in the context of React.
Why interviewers ask this: This is a deeper conceptual question. They want to see if you understand React's paradigm, not just its API.
Model answer: Imperative programming tells the computer how to do something — step by step instructions. Declarative programming tells the computer what you want — the desired end state.
With imperative DOM manipulation, you write code like: "Find the element with id 'counter', get its current text content, parse it as a number, increment it, convert back to string, and set the text content." You're managing every intermediate step.
With React's declarative approach, you write: "The counter should display the value of count." React figures out how to update the DOM to match. When count changes from 5 to 6, React diffs the virtual representations and updates just the text node.
The real-world benefit is predictability. In an imperative system with 20 different event handlers all manipulating the same DOM elements, it's nearly impossible to predict what the DOM looks like at any given moment — the state is implicit in the DOM itself. In React, the state is explicit in your component, and the UI is always a deterministic function of that state. Given the same state, you always get the same UI.
This is why React makes debugging dramatically easier. If a UI bug exists, you look at the state — if the state is correct, the bug is in the render logic; if the state is wrong, the bug is in the state update logic. Two places to look instead of an unknowable number of DOM mutation paths.
Q8. What happens when you call setState in React? Walk through the full process.
Why interviewers ask this: They want to verify you understand React's rendering pipeline, not just the API.
Model answer:
When you call a state setter (like setCount(5)), React doesn't immediately update the component. Here's the full sequence:
First, React enqueues the state update. The new value is stored internally but the component hasn't re-rendered yet. This is why reading state immediately after setting it gives you the old value.
Second, React batches multiple state updates that happen in the same event handler or effect. If you call setCount(5) and setName('Alice') in the same click handler, React combines them into a single re-render, not two.
Third, React triggers a re-render. The component function runs again from top to bottom with the new state values. This produces a new JSX tree — a new Virtual DOM representation.
Fourth, React reconciles the new Virtual DOM tree with the previous one. It walks both trees simultaneously, comparing nodes. It identifies the minimal set of changes: which DOM nodes need to be added, removed, or updated.
Fifth, React commits those changes to the real DOM in a single batch. The browser then paints the updated UI.
Sixth, after the DOM update, React runs any effects (useEffect callbacks) whose dependencies changed.
The important insight is that rendering in React is synchronous and predictable — when the component function runs, all state values are consistent for that render. There's no moment where some state has updated and other state hasn't.
Q9. What is the difference between Real DOM and Virtual DOM?
Why interviewers ask this: Classic React interview question. They want depth beyond "Virtual DOM is faster."
Model answer: The Real DOM is the browser's actual Document Object Model — a tree of HTML elements that the browser parses, lays out, paints, and composites. Every DOM node is a heavy object with hundreds of properties (events, styles, attributes, references). Modifying the Real DOM triggers a cascade: the browser recalculates styles, recomputes layout (reflow), repaints affected pixels, and composites layers.
The Virtual DOM is a lightweight JavaScript representation — plain objects with type, props, and children. No browser APIs, no style computation, no layout. Comparing and creating these objects is pure JavaScript computation, which is orders of magnitude cheaper.
React's process is: generate a new Virtual DOM tree from your component, diff it against the previous tree (reconciliation), compute the minimal set of Real DOM operations needed, and batch-apply them.
But here's the nuance interviewers appreciate: the Virtual DOM isn't a silver bullet. It adds overhead — maintaining two trees and diffing them has a cost. For a single, known DOM change, direct manipulation would be faster. The Virtual DOM's value is that it provides consistent, good-enough performance for the general case without developers needing to manually optimize. It's a trade-off of peak performance for developer experience and reliability.
Frameworks like Svelte prove you can get similar or better performance without a Virtual DOM by shifting work to compile time. React's team has acknowledged this, which is partly why React Server Components and the React compiler (React Forget) are moving toward reducing Virtual DOM overhead.
Q10. How do React components communicate with each other?
Why interviewers ask this: Data flow is fundamental to React architecture. They want to see if you understand the patterns and when to use each.
Model answer: React components communicate through four main patterns, each suited to different relationships:
Props (parent to child): The most common pattern. A parent passes data down as attributes: <UserCard name={user.name} />. This is one-way — the child reads props but never modifies them.
Callback props (child to parent): The parent passes a function as a prop, and the child calls it to send data upward: <SearchBar onSearch={handleSearch} />. When the user types and submits, SearchBar calls onSearch(query), which the parent handles.
Lifting state up (sibling to sibling): Siblings can't communicate directly. You move the shared state to their nearest common parent, which passes it down to both. For example, a Celsius input and Fahrenheit display both need the temperature value — that value lives in their parent component.
Context API (distant components): When data needs to reach deeply nested components without threading through every intermediate level (prop drilling), you use React Context. A Provider wraps the tree, and any descendant Consumer can access the value directly. Common use cases: auth state, theme, locale.
For truly complex global state — like an e-commerce cart that dozens of components need — you might reach for a state management library like Redux or Zustand. But for most applications, these four patterns cover 95% of needs.
Q11. What does "lifting state up" mean in React?
Why interviewers ask this: It tests whether you understand React's data flow principles and can solve common architectural problems.
Model answer: Lifting state up means moving state from a child component to the nearest parent that needs to share it. It's React's answer to the question: "How do sibling components share data?"
Here's a concrete example: You have a search input component and a results list component. They're siblings — both children of a page component. The results list needs to know what the user typed in the search input.
You can't pass data sideways between siblings in React. Instead, you "lift" the search query state up to their shared parent. The parent owns the state, passes the current query to the results list as a prop, and passes a setter function to the search input as a callback prop.
Before (broken — siblings can't communicate):
SearchInput [owns query state] ──✗──→ ResultsList [needs query]
After (lifted state):
Parent [owns query state]
├── SearchInput [receives setQuery callback]
└── ResultsList [receives query as prop]
The principle behind this is React's unidirectional data flow. Data always flows downward through props. When two components need the same data, the data must live at or above their common ancestor.
The downside is that heavily lifting state can lead to prop drilling — passing props through many intermediate components. When that becomes painful, it's a signal to consider Context API or a state management library.
Q12. Explain the project structure of a React application. How would you organize a medium-sized project?
Why interviewers ask this: They're evaluating your architectural thinking and real-world experience.
Model answer: A React project's structure depends on its size and complexity. For a medium-sized project — say 20-30 components, 5-10 pages — I'd use a feature-based organization:
src/
├── features/ # domain-specific code
│ ├── auth/ # login, signup, auth guard
│ │ ├── components/
│ │ ├── hooks/
│ │ └── services/
│ ├── products/ # product listing, detail
│ └── cart/ # cart management
├── shared/ # cross-cutting concerns
│ ├── components/ # Button, Modal, etc.
│ ├── hooks/ # useFetch, useLocalStorage
│ └── utils/ # formatCurrency, validate
├── pages/ # route-level components
├── App.jsx
└── main.jsx
The key principle is co-location — everything related to a feature lives in the same directory. When I'm working on the cart feature, I open one folder and find all its components, hooks, and API calls together.
Shared components — things used across multiple features like Button, Modal, Input — live in a shared/ directory. Pages are thin wrappers that compose feature components together.
For a smaller project (5-10 components), this is overkill. A flat components/ folder works fine. For a larger project (100+ components), you might add more structure: barrel files (index.js) for clean imports, a formal design system package, and stricter boundaries between features.
The most important thing is consistency — whatever structure you pick, the entire team follows it.
Advanced (Q13–Q18)
Q13. React says "composition over inheritance." Explain what this means with practical examples.
Why interviewers ask this: This tests deep understanding of React's design philosophy and OOP concepts.
Model answer:
In traditional OOP, you'd create specialized components by inheriting from a base class: class DangerButton extends Button. In React, you instead create specialized components by wrapping or configuring generic ones.
There are several composition patterns:
Children composition: A Card component accepts any content via children. You don't need ProductCard extends Card — you put product content inside a generic Card.
Props composition: A Button component accepts variant, size, leftIcon props. DangerButton isn't a subclass — it's just <Button variant="danger">. Or you create a wrapper: function DangerButton(props) { return <Button variant="danger" {...props} /> }.
Compound components: A Tabs component uses Context to share state between Tab and TabPanel children. The children compose together without inheritance.
Custom hooks: Instead of inheriting data-fetching behavior from a base class, you compose it via useFetch() or useUser() hooks.
React avoids inheritance because component hierarchies are fragile — they create tight coupling, make refactoring difficult, and the "fragile base class problem" means changes to parent classes break children in unpredictable ways. Composition is more flexible: you can combine any pieces in any order without a rigid hierarchy.
The React team has explicitly stated they've never found a use case where inheritance is better than composition for React components. In practice, I've built large applications (100+ components) without ever using class inheritance.
Q14. How would you decompose a complex UI mockup into React components? Walk through your process.
Why interviewers ask this: This is a practical architecture question. They want to see your systematic thinking process.
Model answer: I follow a five-step process:
Step 1: Draw boxes on the mockup. I start from the outside in. First, identify the major layout sections — header, sidebar, main content, footer. Then within each section, identify repeated patterns and distinct functional areas. Each box becomes a candidate component.
Step 2: Name each box. Use descriptive PascalCase names: ProductGrid, FilterSidebar, SearchBar. If I struggle to name a box, it either does too many things (needs splitting) or too little (should be merged with its parent).
Step 3: Build the component tree. Arrange the named components into a parent-child hierarchy. This reveals data flow requirements: which component needs which data, and where state should live.
Step 4: Identify reuse. Look for components that appear multiple times — these become the most important reusable components. An Avatar appearing in tweets, compose box, and suggestions is an obvious extraction target.
Step 5: Determine the data flow. For each component, identify: what props does it need? Does it have internal state? Does it need to communicate with siblings (lifting state)? Does it fetch data?
The guiding principles are: single responsibility (each component does one thing), start specific and generalize when patterns emerge (don't prematurely abstract), and keep the tree as shallow as possible (deep nesting means complex prop threading).
Q15. Compare React's rendering approach (Virtual DOM) with Svelte's compile-time approach. What are the trade-offs?
Why interviewers ask this: Senior-level question testing framework-agnostic understanding of rendering strategies.
Model answer: React and Svelte represent two fundamentally different approaches to the same problem: efficiently updating the DOM when data changes.
React's approach (runtime diffing): Your components compile to functions that return Virtual DOM descriptions. At runtime, when state changes, React re-runs the component function, produces a new Virtual DOM tree, diffs it against the previous one, and applies the minimal changes to the real DOM.
Svelte's approach (compile-time analysis): The Svelte compiler analyzes your component code at build time and generates imperative JavaScript that surgically updates exactly the DOM nodes that depend on each piece of state. There's no Virtual DOM, no diffing — just direct element.textContent = newValue calls wrapped in reactive update functions.
The trade-offs:
| Aspect | React (Virtual DOM) | Svelte (Compile-time) |
|---|---|---|
| Runtime overhead | Virtual DOM tree creation + diffing on every update | Near-zero — compiled to direct DOM updates |
| Bundle size | ~40KB runtime library | ~2-5KB runtime (compiler does the work at build time) |
| Memory usage | Two Virtual DOM trees in memory | No virtual trees |
| Developer model | Very flexible — any JavaScript expression can be reactive | More constrained — reactivity through assignments and $: labels |
| Ecosystem | Massive — largest component library ecosystem | Growing but much smaller |
| Update granularity | Component-level (re-runs entire component function) | Variable-level (updates only what depends on the changed variable) |
React is betting on the compiler approach too — React Forget (now React Compiler) aims to automatically optimize re-renders at compile time, potentially eliminating the need for useMemo and useCallback. This shows the industry is converging toward compile-time optimization.
Q16. A new developer on your team asks why their component keeps re-rendering. How do you diagnose and explain this?
Why interviewers ask this: Tests practical debugging skills and understanding of React's rendering behavior.
Model answer: First, I'd help them understand that re-rendering is not inherently bad — it's how React works. A re-render means the component function runs again and produces new JSX. React then diffs and only updates the DOM if something actually changed. The question is whether the re-renders are unnecessary and causing performance issues.
To diagnose, I'd use React DevTools Profiler. It highlights components that rendered and shows why — which props or state changed, or whether the parent re-rendered.
Common causes of unnecessary re-renders:
Cause 1: Parent re-renders. By default, when a parent re-renders, all its children re-render too. If the child's props haven't changed, this is wasted work. Solution: wrap the child in React.memo.
Cause 2: New object/array/function references on every render. If a parent passes style={{ color: 'red' }} as a prop, that's a new object every render — React.memo can't help because the prop "changed" (different reference). Solution: move the object outside the component or use useMemo.
Cause 3: State updates at the wrong level. If you store state in App that only ProductCard needs, every keystroke in a search input re-renders the entire app. Solution: move state closer to where it's used.
Cause 4: Context changes. Any component consuming a Context re-renders when the Context value changes — even if it only uses a small part of the value. Solution: split contexts or use a state management library with selector support.
I'd emphasize: optimize only when there's a measured problem. Most re-renders complete in under 1ms and are invisible to users. Profile first, optimize second.
Q17. What are the different rendering strategies in modern React? (CSR, SSR, SSG, ISR)
Why interviewers ask this: Senior-level question about the full spectrum of React rendering options, especially relevant for Next.js roles.
Model answer: Modern React applications can use four rendering strategies, often mixing them within the same app:
Client-Side Rendering (CSR): The traditional SPA approach. The server sends a minimal HTML file with a JavaScript bundle. The browser downloads and executes JavaScript, which renders the UI. Pros: simple deployment, rich interactivity. Cons: slow initial load, poor SEO, blank page until JavaScript loads.
Server-Side Rendering (SSR): The server runs React on every request, generates complete HTML, and sends it to the browser. JavaScript then "hydrates" the HTML to make it interactive. Pros: fast first meaningful paint, good SEO. Cons: server load on every request, Time to Interactive can still be slow.
Static Site Generation (SSG): React runs at build time, generating HTML files for every page. These static files are served from a CDN. Pros: fastest possible load times, zero server compute at runtime, excellent SEO. Cons: only works for content that doesn't change per-request, full rebuild needed for content updates.
Incremental Static Regeneration (ISR): A hybrid. Pages are statically generated at build time but can be re-generated in the background after a configurable time interval. Pros: CDN speed with near-real-time content updates. Cons: users might see stale content briefly, more complex caching behavior.
In practice, Next.js lets you mix these per-page. A marketing homepage might use SSG, a product page might use ISR (revalidating every 60 seconds), a user dashboard might use SSR (personalized on every request), and an interactive editor within the dashboard might use CSR for its dynamic parts.
Q18. If you were starting a new React project in 2026, what technology choices would you make and why?
Why interviewers ask this: Tests holistic understanding of the React ecosystem and ability to make informed architecture decisions.
Model answer: For a production application in 2026, here's my stack and reasoning:
Framework: Next.js (or Remix). Pure client-side React is no longer recommended by the React team for new projects. Next.js provides file-based routing, server-side rendering, API routes, and the best React Server Components support. It handles the infrastructure complexity so you focus on features.
Language: TypeScript. Non-negotiable for any team project. The type safety catches entire categories of bugs at compile time, and the IDE support (autocomplete, refactoring) dramatically improves productivity.
Styling: Tailwind CSS + CSS Modules for complex animations. Tailwind's utility-first approach eliminates naming debates, ensures consistency, and the JIT compiler means zero unused CSS. For complex, stateful animations, I'd use CSS Modules or Framer Motion.
State management: Start with React's built-in tools (useState, useReducer, Context). If global state needs grow, Zustand for its simplicity. Redux Toolkit only if the project has complex, highly structured global state (enterprise dashboards, financial apps).
Data fetching: TanStack Query (React Query). Handles caching, refetching, background updates, optimistic updates — all the hard problems of server state management.
Forms: React Hook Form + Zod. Hook Form for performance (uncontrolled inputs, minimal re-renders), Zod for type-safe validation that integrates with TypeScript.
Testing: Vitest + React Testing Library + Playwright. Vitest for unit tests (fast, Vite-native), React Testing Library for component tests (user-centric), Playwright for end-to-end tests.
The overarching principle: use the tools the React team recommends and the community has converged on. Avoid niche or controversial choices unless you have a strong, specific reason.
Total: 18 interview questions — 6 Beginner, 6 Intermediate, 6 Advanced.