MindForge
MindForge
DashboardHelp & Support
Dashboard
MindForge

Interview Preparation Bootcamp

Course progress

0%
0 of 177 modules complete
Start Here0/1
  • How to Use This Course
Data Structures & Algorithms0/27
  • Arrays and Hashing
  • Two Pointers
  • Sliding Window
  • Sliding Window: Harder Problems
  • Binary Search
  • Stacks
  • Practice Test: Arrays, Pointers, Windows, Search and Stacks
  • Trees: Traversals and Core Patterns
  • Binary Search Trees and Rebuilding a Tree
  • Tries (Prefix Trees)
  • Heaps and Priority Queues
  • Graphs: BFS and DFS
  • Topological Sort and Cycle Detection
  • Union-Find (Disjoint Set Union)
  • Practice Test: Trees, Heaps and Graphs
  • Dynamic Programming Basics
  • Dynamic Programming: Two Dimensions
  • Dynamic Programming: Hard String Matching
  • Backtracking
  • Backtracking: Constraint Satisfaction
  • Greedy Algorithms
  • Interval Problems
  • Bit Manipulation
  • Math and Geometry
  • String Manipulation
  • Pattern Recall and Mock Coding Rounds
  • Practice Test: DP, Backtracking, Greedy and More

System Design

Foundations0/16
  • The System Design Interview Framework
  • Back-of-the-Envelope Estimation
  • Networking and Protocols for Design
  • API Design and Idempotency
  • Load Balancing, Proxies, and Scaling Out
  • Caching and CDNs
  • Choosing a Database: Storage, Indexes and Transactions
  • Replication, Partitioning, and Sharding
  • CAP, PACELC, and Levels of Consistency
  • Messaging, Queues, and Event-Driven Architecture
  • Distributed Transactions and Data Integrity
  • Coordination, Consensus, and Distributed Locks
  • Reliability, Resilience, and Rate Limiting
  • Observability, Security, and Cost
  • System Design Cheat Sheet
  • Practice Test: System Design Foundations
Case Studies0/23
  • Design a URL Shortener
  • Design a Rate Limiter
  • Design a Notification Service
  • Design a Job Queue System
  • Design a Chat App (WhatsApp)
  • Design an Analytics Pipeline
  • Design a Multi-tenant SaaS Architecture
  • Design a Social Media Feed (Twitter/X)
  • Design a Search Autocomplete System
  • Design a File Storage Service (Dropbox)
  • Design Google Docs
  • Design a Code Review System
  • Design Netflix
  • Design YouTube
  • Design Spotify
  • Design Uber/Lyft
  • Design Airbnb
  • Design Ticketmaster (Eventbrite)
  • Design an E-commerce Cart, Checkout, and Catalog
  • Design a Payment System
  • Design a Logging and Monitoring System
  • Mock Design Rounds
  • Practice Test: System Design Case Studies
Low-Level Design0/19
  • The LLD Interview Framework and UML
  • OOP Foundations for Design
  • SOLID Principles
  • Creational Patterns
  • Structural Patterns
  • Behavioral Patterns I — Strategy, Observer, Command, State, Template Method
  • Behavioral Patterns II and Anti-Patterns
  • Concurrency in Low-Level Design
  • Design a Parking Lot
  • Design an Elevator System
  • Design a Movie Ticket Booking System
  • Design an Expense-Sharing App (Splitwise)
  • Design a Vending Machine and an ATM
  • Design a Rate Limiter and a Logging Framework
  • Design a Notification Service and an In-Memory Cache
  • Design Games — Tic-Tac-Toe, Snake and Ladder, Chess
  • Database Design for LLD
  • LLD Cheat Sheet and Recall Drill
  • Practice Test: Low-Level Design

Backend

Python0/5
  • How Python Runs Your Code
  • Functions Deep Dive: Closures, Generators, Context Managers, Scope
  • Classes Deep Dive: Method Types, MRO, Metaclasses
  • Standard Library and Serialization
  • Practice Test: Python
Django0/6
  • Django Request Lifecycle
  • Lab: Django Middleware — Request ID & Response Time
  • Django ORM and Querysets
  • Django's Cache Framework
  • Practice Test: Django
  • Django in Production: Debugging Labs
FastAPI0/5
  • FastAPI, ASGI, and Async
  • FastAPI Dependency Injection
  • FastAPI Background Tasks
  • Lab: FastAPI Async — Concurrent Aggregation
  • Practice Test: FastAPI
Databases (PostgreSQL)0/6
  • Indexing
  • Query Optimization
  • Transactions and Isolation
  • Migrations and Schema Changes
  • Hierarchical Data and Safe Concurrent Updates
  • Practice Test: Databases
Caching, Queues & Distributed Systems0/8
  • Redis Caching
  • Redis Advanced Patterns
  • Celery and Background Workers
  • Kafka and Message Queues
  • Async Pipelines
  • Distributed Systems Basics
  • Distributed Locks
  • Practice Test: Caching, Queues and Distributed Systems
APIs, Security & Deployment0/9
  • REST API Design
  • API Versioning and Error Handling
  • API Security and Authentication
  • WebSockets and Real-Time Systems
  • Docker and Containers
  • File Storage with S3
  • Testing Strategies
  • Mock Backend Round
  • Practice Test: APIs, Security and Deployment
Frontend0/38
  • HTML Document Structure and Semantics
  • CSS Box Model, Flexbox and Grid
  • CSS Architecture and Theming
  • CSS and Rendering Performance
  • Variables, Scope, Hoisting, and Truthiness
  • Functions, this, and Binding
  • Objects and Prototypal Inheritance
  • JavaScript Utility Patterns: Cloning, Caching, and Memory
  • Promises From Scratch
  • The Event Loop and Browser Rendering Pipeline
  • The DOM: Nodes, Events, and Traversal
  • Practice Test: HTML, CSS and JavaScript
  • React Rendering Fundamentals
  • React Hooks Internals
  • React Performance
  • Lab: React — Stateful Counter Component
  • State Management
  • State Machines in React
  • React Custom Hooks and Composition Patterns
  • TypeScript for React
  • React Testing
  • Practice Test: React
  • HTTP and Caching
  • Network Performance and Web Vitals
  • Code Splitting and Bundles
  • Virtualization
  • GraphQL and Data Fetching
  • Web Security
  • WebSockets and Real-time
  • SSR and Next.js
  • Micro-frontends
  • Build Tools and Bundling
  • Accessibility
  • Error Handling
  • Internationalization
  • Animation
  • Rapid Recall and Mock Frontend Rounds
  • Practice Test: Performance, Architecture and Production
Behavioral & Interview Day0/14
  • Resume and Project Walkthroughs
  • The STAR Method and Refining Your Stories
  • Conflict and Difficult Coworkers
  • Failures, Incidents, and Obstacles
  • Leadership, Mentorship, and Ownership
  • Teamwork, Communication, and Feedback
  • Growth and Handling Ambiguity
  • Career Goals, Why This Company, and Negotiation
  • Situational Questions
  • Company Research
  • Mock Behavioral Rounds
  • Interview Day
  • After the Interview
  • Practice Test: Behavioral and Interview Day
React Hooks Internals
Course contents

Interview Preparation Bootcamp

Course progress

0%
0 of 177 modules complete
Start Here0/1
  • How to Use This Course
Data Structures & Algorithms0/27
  • Arrays and Hashing
  • Two Pointers
  • Sliding Window
  • Sliding Window: Harder Problems
  • Binary Search
  • Stacks
  • Practice Test: Arrays, Pointers, Windows, Search and Stacks
  • Trees: Traversals and Core Patterns
  • Binary Search Trees and Rebuilding a Tree
  • Tries (Prefix Trees)
  • Heaps and Priority Queues
  • Graphs: BFS and DFS
  • Topological Sort and Cycle Detection
  • Union-Find (Disjoint Set Union)
  • Practice Test: Trees, Heaps and Graphs
  • Dynamic Programming Basics
  • Dynamic Programming: Two Dimensions
  • Dynamic Programming: Hard String Matching
  • Backtracking
  • Backtracking: Constraint Satisfaction
  • Greedy Algorithms
  • Interval Problems
  • Bit Manipulation
  • Math and Geometry
  • String Manipulation
  • Pattern Recall and Mock Coding Rounds
  • Practice Test: DP, Backtracking, Greedy and More

System Design

Foundations0/16
  • The System Design Interview Framework
  • Back-of-the-Envelope Estimation
  • Networking and Protocols for Design
  • API Design and Idempotency
  • Load Balancing, Proxies, and Scaling Out
  • Caching and CDNs
  • Choosing a Database: Storage, Indexes and Transactions
  • Replication, Partitioning, and Sharding
  • CAP, PACELC, and Levels of Consistency
  • Messaging, Queues, and Event-Driven Architecture
  • Distributed Transactions and Data Integrity
  • Coordination, Consensus, and Distributed Locks
  • Reliability, Resilience, and Rate Limiting
  • Observability, Security, and Cost
  • System Design Cheat Sheet
  • Practice Test: System Design Foundations
Case Studies0/23
  • Design a URL Shortener
  • Design a Rate Limiter
  • Design a Notification Service
  • Design a Job Queue System
  • Design a Chat App (WhatsApp)
  • Design an Analytics Pipeline
  • Design a Multi-tenant SaaS Architecture
  • Design a Social Media Feed (Twitter/X)
  • Design a Search Autocomplete System
  • Design a File Storage Service (Dropbox)
  • Design Google Docs
  • Design a Code Review System
  • Design Netflix
  • Design YouTube
  • Design Spotify
  • Design Uber/Lyft
  • Design Airbnb
  • Design Ticketmaster (Eventbrite)
  • Design an E-commerce Cart, Checkout, and Catalog
  • Design a Payment System
  • Design a Logging and Monitoring System
  • Mock Design Rounds
  • Practice Test: System Design Case Studies
Low-Level Design0/19
  • The LLD Interview Framework and UML
  • OOP Foundations for Design
  • SOLID Principles
  • Creational Patterns
  • Structural Patterns
  • Behavioral Patterns I — Strategy, Observer, Command, State, Template Method
  • Behavioral Patterns II and Anti-Patterns
  • Concurrency in Low-Level Design
  • Design a Parking Lot
  • Design an Elevator System
  • Design a Movie Ticket Booking System
  • Design an Expense-Sharing App (Splitwise)
  • Design a Vending Machine and an ATM
  • Design a Rate Limiter and a Logging Framework
  • Design a Notification Service and an In-Memory Cache
  • Design Games — Tic-Tac-Toe, Snake and Ladder, Chess
  • Database Design for LLD
  • LLD Cheat Sheet and Recall Drill
  • Practice Test: Low-Level Design

Backend

Python0/5
  • How Python Runs Your Code
  • Functions Deep Dive: Closures, Generators, Context Managers, Scope
  • Classes Deep Dive: Method Types, MRO, Metaclasses
  • Standard Library and Serialization
  • Practice Test: Python
Django0/6
  • Django Request Lifecycle
  • Lab: Django Middleware — Request ID & Response Time
  • Django ORM and Querysets
  • Django's Cache Framework
  • Practice Test: Django
  • Django in Production: Debugging Labs
FastAPI0/5
  • FastAPI, ASGI, and Async
  • FastAPI Dependency Injection
  • FastAPI Background Tasks
  • Lab: FastAPI Async — Concurrent Aggregation
  • Practice Test: FastAPI
Databases (PostgreSQL)0/6
  • Indexing
  • Query Optimization
  • Transactions and Isolation
  • Migrations and Schema Changes
  • Hierarchical Data and Safe Concurrent Updates
  • Practice Test: Databases
Caching, Queues & Distributed Systems0/8
  • Redis Caching
  • Redis Advanced Patterns
  • Celery and Background Workers
  • Kafka and Message Queues
  • Async Pipelines
  • Distributed Systems Basics
  • Distributed Locks
  • Practice Test: Caching, Queues and Distributed Systems
APIs, Security & Deployment0/9
  • REST API Design
  • API Versioning and Error Handling
  • API Security and Authentication
  • WebSockets and Real-Time Systems
  • Docker and Containers
  • File Storage with S3
  • Testing Strategies
  • Mock Backend Round
  • Practice Test: APIs, Security and Deployment
Frontend0/38
  • HTML Document Structure and Semantics
  • CSS Box Model, Flexbox and Grid
  • CSS Architecture and Theming
  • CSS and Rendering Performance
  • Variables, Scope, Hoisting, and Truthiness
  • Functions, this, and Binding
  • Objects and Prototypal Inheritance
  • JavaScript Utility Patterns: Cloning, Caching, and Memory
  • Promises From Scratch
  • The Event Loop and Browser Rendering Pipeline
  • The DOM: Nodes, Events, and Traversal
  • Practice Test: HTML, CSS and JavaScript
  • React Rendering Fundamentals
  • React Hooks Internals
  • React Performance
  • Lab: React — Stateful Counter Component
  • State Management
  • State Machines in React
  • React Custom Hooks and Composition Patterns
  • TypeScript for React
  • React Testing
  • Practice Test: React
  • HTTP and Caching
  • Network Performance and Web Vitals
  • Code Splitting and Bundles
  • Virtualization
  • GraphQL and Data Fetching
  • Web Security
  • WebSockets and Real-time
  • SSR and Next.js
  • Micro-frontends
  • Build Tools and Bundling
  • Accessibility
  • Error Handling
  • Internationalization
  • Animation
  • Rapid Recall and Mock Frontend Rounds
  • Practice Test: Performance, Architecture and Production
Behavioral & Interview Day0/14
  • Resume and Project Walkthroughs
  • The STAR Method and Refining Your Stories
  • Conflict and Difficult Coworkers
  • Failures, Incidents, and Obstacles
  • Leadership, Mentorship, and Ownership
  • Teamwork, Communication, and Feedback
  • Growth and Handling Ambiguity
  • Career Goals, Why This Company, and Negotiation
  • Situational Questions
  • Company Research
  • Mock Behavioral Rounds
  • Interview Day
  • After the Interview
  • Practice Test: Behavioral and Interview Day
Browsing without an account — progress is saved in this browser only.Sign in to save it

React Hooks Internals

Reading30 min

Anyone can call useState. What separates a mid-level candidate from a senior one is being able to explain how it works, where the state actually lives, why the Rules of Hooks exist, and why breaking them corrupts state silently instead of throwing a helpful error. This lesson builds simplified versions of useState and useEffect so the internals stop being magic.

Where state actually lives

State does not live "in" your component function. Your function gets called fresh on every render, so any local variable inside it is discarded and recreated each time. State actually lives on the Fiber node, React's internal per-component data structure, as a linked list of hook entries. Picture a numbered coat check: your component hands over its state each render and gets a numbered ticket back, always the same ticket for the same hook call, so it always retrieves the same coat.

The sequence: React calls your component function, reads the next hook slot in the fiber's hook list, in call order, and returns whatever's stored there. You call the setter with a new value; React stores the pending update and schedules a re-render for that fiber. On the scheduled render, React calls your function again, and useState reads the same hook slot, now updated, and hands back the new value.

tsx
// A teaching approximation, not real React source.
let hooks: any[] = [];
let currentHookIndex = 0;

function useStateSimplified<T>(initialValue: T): [T, (v: T | ((prev: T) => T)) => void] {
  const hookIndex = currentHookIndex;
  hooks[hookIndex] = hooks[hookIndex] ?? initialValue;

  const setState = (newValue: T | ((prev: T) => T)) => {
    hooks[hookIndex] = typeof newValue === 'function' ? (newValue as (prev: T) => T)(hooks[hookIndex]) : newValue;
    scheduleRerender();
  };

  currentHookIndex++;
  return [hooks[hookIndex], setState];
}

function scheduleRerender() {
  queueMicrotask(() => {
    currentHookIndex = 0; // reset so the next render reads hooks back in the same order
    renderApp();
  });
}

The key insight is that hooks[hookIndex] persists across calls, because it lives outside the function that gets re-invoked each time. Real React stores this per-fiber rather than in one global array, but "index into a persistent list" is exactly the right model. Does calling the setter with the same value still trigger a re-render? In React 18+, function-component useState bails out of re-rendering when the new value is Object.is-equal to the current one; it still calls the function once to check, then skips the commit if nothing changed. Note it's Object.is, not ===, which matters for NaN and -0.

Remember: state lives on the fiber, addressed by call-order index, not inside your function. Your function is discarded and rebuilt every render.

Sign in to try this knowledge check.

How useEffect tracks its dependency array

useEffect also claims a slot in the fiber's hook list, storing both the effect function and the last dependency array. After every commit, React compares the new array to the stored one, element by element, with Object.is. If any element differs, or there was no previous array at all, the old cleanup runs first, then the new effect runs.

tsx
function useEffectSimplified(effect: () => void | (() => void), deps?: unknown[]) {
  const hookIndex = currentHookIndex;
  const prevDeps = hooks[hookIndex]?.deps;
  const hasChanged = !prevDeps || !deps || deps.some((dep, i) => !Object.is(dep, prevDeps[i]));

  if (hasChanged) {
    scheduleEffect(() => {
      hooks[hookIndex]?.cleanup?.();
      const cleanup = effect();
      hooks[hookIndex] = { deps, cleanup };
    });
  }
  currentHookIndex++;
}

The three shapes of dependency array mean three different things: no array at all runs the effect after every render; an empty array runs it once, after the first commit; a populated array runs it whenever any listed value changes, by Object.is.

tsx
useEffect(() => { /* ... */ });           // every render
useEffect(() => { /* ... */ }, []);        // once, after first commit
useEffect(() => { /* ... */ }, [userId]);  // whenever userId changes

Remember: useEffect compares its dependency array element by element with Object.is after every commit. Any difference reruns the effect.

Sign in to try this knowledge check.

The dependency array is about correctness, not performance

The array's real job is telling React when the closure's captured values have gone stale, not tuning how often something runs.

tsx
// WRONG: missing dependency, stale closure over `userId`
useEffect(() => {
  fetchUser(userId).then(setUser);
}, []); // eslint would flag this

// RIGHT: effect re-runs whenever userId changes, no stale data
useEffect(() => {
  let cancelled = false;
  fetchUser(userId).then((u) => { if (!cancelled) setUser(u); });
  return () => { cancelled = true; }; // cleanup avoids setting state after unmount
}, [userId]);

The wrong version keeps calling fetchUser with whatever userId was on the very first render, forever, because the closure captured that value once and the empty array tells React never to re-run and capture a fresh one. The fix is not "add a comment explaining the omission," it is including userId in the array so the effect actually sees the current value. The cancelled flag in the fixed version solves a separate, related problem: if userId changes again before the first fetch resolves, or the component unmounts, that stale response is not allowed to call setUser after the fact.

Remember: a missing dependency is a stale-data bug, not a missed performance tweak. The array tells React when a closure has gone stale.

Sign in to try this knowledge check.

A version you can actually run

tsx
type EffectRecord = { deps?: unknown[]; cleanup?: (() => void) | void };

function createHookSystem() {
  let state: unknown[] = [];
  let effects: EffectRecord[] = [];
  let stateIndex = 0;
  let effectIndex = 0;
  let renderFn: () => void = () => {};

  function useState<T>(initial: T): [T, (v: T | ((p: T) => T)) => void] {
    const i = stateIndex++;
    if (state[i] === undefined) state[i] = initial;
    const setValue = (v: T | ((p: T) => T)) => {
      const next = typeof v === 'function' ? (v as (p: T) => T)(state[i] as T) : v;
      if (!Object.is(state[i], next)) { state[i] = next; rerender(); }
    };
    return [state[i] as T, setValue];
  }

  function useEffect(effect: () => void | (() => void), deps?: unknown[]) {
    const i = effectIndex++;
    const prev = effects[i];
    const changed = !prev || !deps || deps.some((d, idx) => !Object.is(d, prev.deps?.[idx]));
    if (changed) {
      queueMicrotask(() => {
        if (typeof prev?.cleanup === 'function') prev.cleanup();
        const cleanup = effect();
        effects[i] = { deps, cleanup };
      });
    } else {
      effects[i] = prev;
    }
  }

  function rerender() { stateIndex = 0; effectIndex = 0; renderFn(); }
  function mount(fn: () => void) { renderFn = fn; rerender(); }
  return { useState, useEffect, mount };
}

const { useState, useEffect, mount } = createHookSystem();
function App() {
  const [seconds, setSeconds] = useState(0);
  useEffect(() => {
    const id = setInterval(() => setSeconds(s => s + 1), 1000);
    return () => clearInterval(id); // runs before the next effect, and on unmount
  }, []); // empty deps: subscribe once
  console.log('seconds:', seconds);
}
mount(App);

Why hooks can't be conditional

Hooks are read by positional index, never by name. React has no idea your third useState call is "the username state," it only knows "slot 3 in this fiber's hook list." If a hook call gets skipped on some renders, inside an if, a loop, or after an early return, every hook after it shifts down one slot, and React reads the wrong stored value into the wrong hook.

tsx
// BROKEN — do not do this
function Broken({ showExtra }: { showExtra: boolean }) {
  const [name, setName] = useState('a');
  if (showExtra) {
    const [extra, setExtra] = useState('b'); // hook 2 only exists sometimes
  }
  const [age, setAge] = useState(0); // this is hook slot 2 OR 3 depending on showExtra!
}

When showExtra flips between renders, age's slot index shifts with it, so React hands it whatever value extra had stored instead. This is exactly why the ESLint rule react-hooks/rules-of-hooks exists and should never be disabled: the bug it prevents is silent state corruption, not a crash you'd catch in normal testing. The fix is always to keep every hook call unconditional and push the condition inside the hook instead:

tsx
function Fixed({ showExtra }: { showExtra: boolean }) {
  const [name, setName] = useState('a');
  const [extra, setExtra] = useState('b'); // always called
  const [age, setAge] = useState(0);
  const displayExtra = showExtra ? extra : null; // condition applied to the VALUE, not the call
}

Remember: hooks are read by call-order index, never by name. Skip a call on some renders, and every hook after it silently shifts to the wrong slot.

Sign in to try this knowledge check.
PreviousReact Rendering FundamentalsNextReact Performance

Course progress

0%
0 of 177 modules complete

On this page

  • Where state actually lives
  • How useEffect tracks its dependency array
  • The dependency array is about correctness, not performance
  • A version you can actually run
  • Why hooks can't be conditional