<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:cc="http://cyber.law.harvard.edu/rss/creativeCommonsRssModule.html">
    <channel>
        <title><![CDATA[Stories by Biki Das on Medium]]></title>
        <description><![CDATA[Stories by Biki Das on Medium]]></description>
        <link>https://medium.com/@bikid475?source=rss-3ac124cb043------2</link>
        <image>
            <url>https://cdn-images-1.medium.com/fit/c/150/150/1*Yg3nEt--kRSdodif5X3GQg@2x.jpeg</url>
            <title>Stories by Biki Das on Medium</title>
            <link>https://medium.com/@bikid475?source=rss-3ac124cb043------2</link>
        </image>
        <generator>Medium</generator>
        <lastBuildDate>Mon, 22 Jun 2026 06:28:52 GMT</lastBuildDate>
        <atom:link href="https://medium.com/@bikid475/feed" rel="self" type="application/rss+xml"/>
        <webMaster><![CDATA[yourfriends@medium.com]]></webMaster>
        <atom:link href="http://medium.superfeedr.com" rel="hub"/>
        <item>
            <title><![CDATA[Virtual DOM & Fiber Architecture: React’s Secret Performance Engine]]></title>
            <link>https://medium.com/@bikid475/react-internals-how-virtual-dom-and-fiber-work-together-1619721ae96f?source=rss-3ac124cb043------2</link>
            <guid isPermaLink="false">https://medium.com/p/1619721ae96f</guid>
            <category><![CDATA[virtual-dom]]></category>
            <category><![CDATA[react-fiber]]></category>
            <category><![CDATA[react]]></category>
            <dc:creator><![CDATA[Biki Das]]></dc:creator>
            <pubDate>Sun, 16 Nov 2025 19:24:42 GMT</pubDate>
            <atom:updated>2025-11-21T07:03:38.810Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/1024/1*-prpXIh9kr1tRXyQDxaPYw.png" /></figure><p>Last year, I submitted a <a href="https://github.com/facebook/react/pull/29600">PR</a> to React’s Fiber lanes implementation — mainly fixing a higherPriorityLane call and adding a few related tests. It ultimately got closed, but that ended up being the most valuable learning experience of my React career.</p><p>Digging into React’s source code, stepping through its priority scheduling system, and understanding why my approach didn’t align with the deeper reconciliation model taught me far more about how React actually works under the hood than years of application-level coding ever did.</p><p>Even though the PR wasn’t merged, the process gave me a much deeper appreciation of Fiber, lanes, and how React’s concurrency model is designed — and it’s shaped the way I write and reason about React code today.</p><p>Most developers (myself included, until recently) treat React as a black box. We know it uses a “Virtual DOM” and does some “diffing magic,” but the details feel academic — until they’re not. Until you’re debugging a performance issue, or wondering why your state updates aren’t batching the way you expect, or trying to understand why that useTransition hook makes your UI feel so much smoother.</p><p>So let me share what I learned from that PR. This isn’t just about Fiber lanes or reconciliation algorithms — it’s about understanding the mental model that powers every React application you’ll ever build.</p><p><em>Understanding React’s core algorithm and why it matters for writing performant code</em></p><p>You’ve heard it a thousand times:</p><blockquote><em>React uses a Virtual DOM for performance.</em></blockquote><p>But when pressed for details, most developers hand-wave something about “diffing” and “batching updates.” The truth is far more fascinating. React’s Fiber architecture is a complete rewrite of React’s core algorithm, introducing concepts like time-slicing, priority scheduling, and interruptible rendering that fundamentally change how we should think about React performance.</p><p>Understanding <strong>Fiber</strong> isn’t just academic curiosity — it directly impacts how you write performant React code. When you know how React schedules work, prioritizes updates, and decides what to render when, you can structure your components and state updates to work with React’s algorithm instead of against it. This deep dive reveals the inner workings that power every React application.</p><h3>The Virtual DOM: More Than a Feeling</h3><p>The Virtual DOM isn’t just a performance optimization — it’s a programming model that enables declarative UI:</p><pre>// What the Virtual DOM actually is<br>interface VirtualNode {<br>  type: string | ComponentType; // &#39;div&#39; or MyComponent<br>  props: Record&lt;string, any&gt;; // Including children<br>  key: string | null; // For list reconciliation<br>  ref: any; // Ref attachments<br>}<br><br>// Simplified Virtual DOM creation<br>function createElement(<br>  type: string | ComponentType,<br>  props: Record&lt;string, any&gt; | null,<br>  ...children: any[]<br>): VirtualNode {<br>  return {<br>    type,<br>    props: {<br>      ...props,<br>      children: children.length === 1 ? children[0] : children,<br>    },<br>    key: props?.key || null,<br>    ref: props?.ref || null,<br>  };<br>}<br><br>// What JSX compiles to<br>const jsxElement = &lt;div className=&quot;card&quot;&gt;Hello&lt;/div&gt;;<br><br>// Becomes:<br>const virtualElement = createElement(&#39;div&#39;, { className: &#39;card&#39; }, &#39;Hello&#39;);<br><br>// Component Virtual DOM<br>const ComponentVDOM = createElement(<br>  MyComponent,<br>  { name: &#39;React&#39; },<br>  createElement(&#39;span&#39;, null, &#39;Child&#39;),<br>);</pre><h3>The Reconciliation Process</h3><pre>// Simplified reconciliation algorithm<br>class SimpleReconciler {<br>  reconcile(<br>    oldVNode: VirtualNode | null,<br>    newVNode: VirtualNode | null,<br>    container: HTMLElement,<br>  ): void {<br>    // Deletion<br>    if (oldVNode &amp;&amp; !newVNode) {<br>      this.removeNode(oldVNode, container);<br>      return;<br>    }<br><br>    // Addition<br>    if (!oldVNode &amp;&amp; newVNode) {<br>      this.createNode(newVNode, container);<br>      return;<br>    }<br><br>    // Update<br>    if (oldVNode &amp;&amp; newVNode) {<br>      // Different types: replace entirely<br>      if (oldVNode.type !== newVNode.type) {<br>        this.removeNode(oldVNode, container);<br>        this.createNode(newVNode, container);<br>        return;<br>      }<br><br>      // Same type: update properties and recurse on children<br>      this.updateNode(oldVNode, newVNode, container);<br>      this.reconcileChildren(oldVNode, newVNode, container);<br>    }<br>  }<br><br>  private reconcileChildren(<br>    oldVNode: VirtualNode,<br>    newVNode: VirtualNode,<br>    container: HTMLElement,<br>  ): void {<br>    const oldChildren = Array.isArray(oldVNode.props.children)<br>      ? oldVNode.props.children<br>      : [oldVNode.props.children];<br><br>    const newChildren = Array.isArray(newVNode.props.children)<br>      ? newVNode.props.children<br>      : [newVNode.props.children];<br><br>    // Key-based reconciliation for lists<br>    if (this.hasKeys(newChildren)) {<br>      this.reconcileKeyedChildren(oldChildren, newChildren, container);<br>    } else {<br>      // Index-based reconciliation (less efficient)<br>      this.reconcileIndexedChildren(oldChildren, newChildren, container);<br>    }<br>  }<br><br>  private reconcileKeyedChildren(<br>    oldChildren: VirtualNode[],<br>    newChildren: VirtualNode[],<br>    container: HTMLElement,<br>  ): void {<br>    // Build key maps for efficient lookup<br>    const oldKeyMap = new Map&lt;string, VirtualNode&gt;();<br>    oldChildren.forEach((child) =&gt; {<br>      if (child.key) oldKeyMap.set(child.key, child);<br>    });<br><br>    newChildren.forEach((newChild, index) =&gt; {<br>      const oldChild = oldKeyMap.get(newChild.key!);<br><br>      if (oldChild) {<br>        // Reuse existing node<br>        this.updateNode(oldChild, newChild, container);<br>        oldKeyMap.delete(newChild.key!);<br>      } else {<br>        // Create new node<br>        this.createNode(newChild, container);<br>      }<br>    });<br><br>    // Remove unused old nodes<br>    oldKeyMap.forEach((oldChild) =&gt; {<br>      this.removeNode(oldChild, container);<br>    });<br>  }<br>}</pre><h3>Fiber Architecture: The Game Changer</h3><p>Fiber reimagines React’s reconciliation algorithm as an incremental, interruptible process:</p><pre>// Fiber node structure (simplified)<br>interface FiberNode {<br>  // Instance<br>  tag: WorkTag; // Component type (Function, Class, Host, etc.)<br>  type: any; // Component constructor or DOM tag<br>  stateNode: any; // DOM node or class instance<br><br>  // Props and state<br>  pendingProps: any; // New props<br>  memoizedProps: any; // Previous props<br>  memoizedState: any; // Current state<br>  updateQueue: UpdateQueue | null; // Pending state updates<br><br>  // Effects<br>  flags: Flags; // Side effects to perform<br>  subtreeFlags: Flags; // Aggregated flags from subtree<br>  deletions: FiberNode[] | null; // Children to delete<br><br>  // Tree structure<br>  return: FiberNode | null; // Parent fiber<br>  child: FiberNode | null; // First child<br>  sibling: FiberNode | null; // Next sibling<br>  index: number; // Position in parent<br><br>  // Work in progress<br>  alternate: FiberNode | null; // Double buffering<br><br>  // Time and priority<br>  lanes: Lanes; // Priority of this update<br>  childLanes: Lanes; // Priority of children<br>  expirationTime: number; // When this work expires<br>}<br><br>// Work tags identify fiber type<br>enum WorkTag {<br>  FunctionComponent = 0,<br>  ClassComponent = 1,<br>  HostRoot = 3, // Root of the tree<br>  HostComponent = 5, // DOM elements<br>  HostText = 6, // Text nodes<br>  Fragment = 7,<br>  Mode = 8,<br>  ContextConsumer = 9,<br>  ContextProvider = 10,<br>  ForwardRef = 11,<br>  Profiler = 12,<br>  SuspenseComponent = 13,<br>  MemoComponent = 14,<br>  SimpleMemoComponent = 15,<br>  LazyComponent = 16,<br>}<br><br>// Flags track side effects<br>enum Flags {<br>  NoFlags = 0b0000000000000000000,<br>  PerformedWork = 0b0000000000000000001,<br>  Placement = 0b0000000000000000010,<br>  Update = 0b0000000000000000100,<br>  Deletion = 0b0000000000000001000,<br>  ChildDeletion = 0b0000000000000010000,<br>  ContentReset = 0b0000000000000100000,<br>  Callback = 0b0000000000001000000,<br>  DidCapture = 0b0000000000010000000,<br>  Ref = 0b0000000000100000000,<br>  Snapshot = 0b0000000001000000000,<br>  Passive = 0b0000000010000000000,<br>  LayoutMask = Update | Callback | Ref | Snapshot,<br>  PassiveMask = Passive | ChildDeletion,<br>}</pre><h3>The Fiber Work Loop</h3><pre>// Simplified Fiber work loop<br>class FiberScheduler {<br>  private workInProgressRoot: FiberNode | null = null;<br>  private workInProgress: FiberNode | null = null;<br>  private remainingExpirationTime: number = NoWork;<br>  private nextUnitOfWork: FiberNode | null = null;<br><br>  // Main work loop - can be interrupted<br>  workLoop(deadline: IdleDeadline): void {<br>    while (this.nextUnitOfWork !== null &amp;&amp; (deadline.timeRemaining() &gt; 0 || deadline.didTimeout)) {<br>      this.nextUnitOfWork = this.performUnitOfWork(this.nextUnitOfWork);<br>    }<br><br>    if (this.nextUnitOfWork === null) {<br>      // All work complete, commit to DOM<br>      this.completeRoot();<br>    } else {<br>      // More work to do, schedule continuation<br>      requestIdleCallback((deadline) =&gt; this.workLoop(deadline));<br>    }<br>  }<br><br>  // Process one fiber node<br>  private performUnitOfWork(fiber: FiberNode): FiberNode | null {<br>    // Phase 1: Begin work (traverse down)<br>    const next = this.beginWork(fiber);<br><br>    if (next !== null) {<br>      // Continue with child<br>      return next;<br>    }<br><br>    // No children, complete this fiber<br>    let completedWork: FiberNode | null = fiber;<br><br>    while (completedWork !== null) {<br>      // Phase 2: Complete work (traverse up)<br>      const returnFiber = completedWork.return;<br>      const siblingFiber = completedWork.sibling;<br><br>      this.completeWork(completedWork);<br><br>      if (siblingFiber !== null) {<br>        // Continue with sibling<br>        return siblingFiber;<br>      }<br><br>      // Continue completing parent<br>      completedWork = returnFiber;<br>    }<br><br>    return null;<br>  }<br><br>  private beginWork(fiber: FiberNode): FiberNode | null {<br>    switch (fiber.tag) {<br>      case WorkTag.FunctionComponent:<br>        return this.updateFunctionComponent(fiber);<br><br>      case WorkTag.ClassComponent:<br>        return this.updateClassComponent(fiber);<br><br>      case WorkTag.HostComponent:<br>        return this.updateHostComponent(fiber);<br><br>      case WorkTag.SuspenseComponent:<br>        return this.updateSuspenseComponent(fiber);<br><br>      default:<br>        return null;<br>    }<br>  }<br><br>  private updateFunctionComponent(fiber: FiberNode): FiberNode | null {<br>    const Component = fiber.type;<br>    const props = fiber.pendingProps;<br><br>    // Call the function component<br>    const children = Component(props);<br><br>    // Reconcile children<br>    return this.reconcileChildren(fiber, children);<br>  }<br><br>  private completeWork(fiber: FiberNode): void {<br>    // Mark effects that need to be applied<br>    if (fiber.flags &amp; Flags.Update) {<br>      this.markUpdate(fiber);<br>    }<br><br>    if (fiber.flags &amp; Flags.Placement) {<br>      this.markPlacement(fiber);<br>    }<br><br>    if (fiber.flags &amp; Flags.Deletion) {<br>      this.markDeletion(fiber);<br>    }<br><br>    // Bubble up effects to parent<br>    if (fiber.return !== null) {<br>      fiber.return.flags |= fiber.flags;<br>      fiber.return.subtreeFlags |= fiber.subtreeFlags;<br>    }<br>  }<br><br>  // Commit phase - apply all effects to DOM<br>  private completeRoot(): void {<br>    const finishedWork = this.workInProgressRoot;<br>    if (finishedWork === null) return;<br><br>    // Commit all effects<br>    this.commitRoot(finishedWork);<br><br>    // Reset for next update<br>    this.workInProgressRoot = null;<br>    this.workInProgress = null;<br>  }<br><br>  private commitRoot(root: FiberNode): void {<br>    // Phase 1: Before mutation (getSnapshotBeforeUpdate)<br>    this.commitBeforeMutationEffects(root);<br><br>    // Phase 2: Mutation (DOM updates)<br>    this.commitMutationEffects(root);<br><br>    // Swap the tree<br>    root.current = root.alternate;<br><br>    // Phase 3: Layout (componentDidMount/Update)<br>    this.commitLayoutEffects(root);<br>  }<br>}</pre><h3>The Complete Picture: How React’s Systems Work Together</h3><h4>Understanding the Flow: A Bird’s Eye View</h4><p>Most React explanations show you individual pieces — the Virtual DOM, Fiber nodes, the scheduler — but miss the crucial part: <strong>how they all connect</strong>. Let’s fix that.</p><h4>The Four Systems and How They Connect</h4><p>React’s performance story has four interconnected systems:</p><ol><li><strong>Update Queue System</strong> — Collects state changes</li><li><strong>Batching System</strong> — Groups updates together</li><li><strong>Scheduling System</strong> — Decides when work happens</li><li><strong>Reconciliation System</strong> — Figures out what changed</li></ol><p>Here’s how they work together:</p><pre>┌─────────────────────────────────────────────────────────┐<br>│                    USER ACTION                          │<br>│                  (click, type, etc.)                    │<br>└─────────────────────────────────────────────────────────┘<br>                          ↓<br>┌─────────────────────────────────────────────────────────┐<br>│ SYSTEM 1: UPDATE QUEUE                                  │<br>│                                                          │<br>│ setState(1) → Create update object                      │<br>│ setState(2) → Create update object                      │  <br>│ setState(3) → Create update object                      │<br>│                                                          │<br>│ All stored in: fiber.updateQueue.shared.pending         │<br>│ Structure: Circular linked list                         │<br>└─────────────────────────────────────────────────────────┘<br>                          ↓<br>┌─────────────────────────────────────────────────────────┐<br>│ SYSTEM 2: BATCHING                                      │<br>│                                                          │<br>│ Question: Schedule reconciliation now or wait?          │<br>│                                                          │<br>│ If executionContext has BatchedContext flag:            │<br>│   → WAIT (don&#39;t schedule yet)                          │<br>│                                                          │<br>│ When batching context ends:                             │<br>│   → NOW schedule (once for all updates)                │<br>└─────────────────────────────────────────────────────────┘<br>                          ↓<br>┌─────────────────────────────────────────────────────────┐<br>│ SYSTEM 3: SCHEDULING                                    │<br>│                                                          │<br>│ scheduleUpdateOnFiber() is called                       │<br>│   ↓                                                      │<br>│ Convert lane → scheduler priority                       │<br>│   ↓                                                      │<br>│ scheduleCallback(priority, performWorkOnRoot)           │<br>│   ↓                                                      │<br>│ Task created and pushed to scheduler&#39;s taskQueue        │<br>│                                                          │<br>│ Scheduler decides WHEN to execute based on priority     │<br>└─────────────────────────────────────────────────────────┘<br>                          ↓<br>┌─────────────────────────────────────────────────────────┐<br>│ SYSTEM 4: RECONCILIATION                                │<br>│                                                          │<br>│ performWorkOnRoot() executes                            │<br>│   ↓                                                      │<br>│ For each fiber in tree:                                 │<br>│   • Process updates from updateQueue                    │<br>│   • Render component → new Virtual DOM                  │<br>│   • Diff with old Virtual DOM                           │<br>│   • Mark changes (flags)                                │<br>│   • Check: Should we pause? (priority check)            │<br>│   ↓                                                      │<br>│ Build work-in-progress tree with all changes marked     │<br>│   ↓                                                      │<br>│ Commit: Apply changes to DOM                            │<br>└─────────────────────────────────────────────────────────┘</pre><h4>System 1: The Update Queue</h4><p>Every Fiber node has an update queue where state changes accumulate:</p><pre>// Update queue structure<br>interface UpdateQueue&lt;State&gt; {<br>  baseState: State;           // Starting state<br>  shared: {<br>    pending: Update | null;   // Circular linked list of updates<br>  };<br>}<br><br>interface Update&lt;State&gt; {<br>  lane: Lane;                 // Priority (SyncLane, TransitionLane, etc.)<br>  action: State | ((prev: State) =&gt; State);<br>  next: Update | null;        // Next update in circular list<br>}<br><br>// When setState is called<br>function setState(newState) {<br>  // 1. Create update object<br>  const update = {<br>    lane: requestUpdateLane(),  // Gets current priority context<br>    action: newState,<br>    next: null<br>  };<br><br>  // 2. Add to fiber&#39;s circular linked list<br>  const fiber = getCurrentFiber();<br>  const pending = fiber.updateQueue.shared.pending;<br>  <br>  if (pending === null) {<br>    update.next = update;  // Points to itself (circular)<br>  } else {<br>    update.next = pending.next;  // Insert into circle<br>    pending.next = update;<br>  }<br>  <br>  fiber.updateQueue.shared.pending = update;  // Points to last update<br><br>  // 3. Try to schedule (goes to System 2: Batching)<br>  scheduleUpdateOnFiber(fiber, update.lane);<br>}</pre><h4>System 2: The Batching Mechanism</h4><p><strong>Batching is NOT about scheduler timeouts</strong> — it’s about delaying the scheduling call itself.</p><pre>// React tracks execution context with flags<br>let executionContext = NoContext;<br><br>const NoContext = 0b000;<br>const BatchedContext = 0b001;   // &quot;We&#39;re batching&quot;<br>const RenderContext = 0b010;     // &quot;We&#39;re reconciling&quot;<br>const CommitContext = 0b100;     // &quot;We&#39;re committing&quot;<br><br>// React wraps event handlers<br>function dispatchEvent(nativeEvent) {<br>  // Turn ON batching flag<br>  const previousContext = executionContext;<br>  executionContext |= BatchedContext;<br><br>  try {<br>    // Your event handler runs here<br>    // All setState calls happen inside this try block<br>    invokeGuardedCallback(userProvidedEventHandler, nativeEvent);<br>  } finally {<br>    // Turn OFF batching flag<br>    executionContext = previousContext;<br><br>    // THIS IS THE KEY MOMENT<br>    if (executionContext === NoContext) {<br>      // Batching is complete, now schedule all accumulated updates<br>      flushSyncCallbackQueue();<br>    }<br>  }<br>}<br><br>// Inside setState&#39;s scheduling logic<br>function scheduleUpdateOnFiber(fiber, lane) {<br>  const root = markUpdateLaneFromFiberToRoot(fiber, lane);<br><br>  // CHECK: Are we batching?<br>  if (executionContext &amp; BatchedContext) {<br>    // YES - Don&#39;t schedule yet, just return<br>    // The update is already in the queue, it will be<br>    // scheduled when the batch ends (in the finally block above)<br>    return;<br>  }<br><br>  // NO - Schedule immediately (goes to System 3)<br>  ensureRootIsScheduled(root, lane);<br>}</pre><p>Why batching happens:</p><pre>// Example: Three setState calls<br>function handleClick() {<br>  setState(1);  // Added to queue, scheduleUpdateOnFiber sees BatchedContext, returns<br>  setState(2);  // Added to queue, scheduleUpdateOnFiber sees BatchedContext, returns<br>  setState(3);  // Added to queue, scheduleUpdateOnFiber sees BatchedContext, returns<br>  // Function ends → finally block executes → flushSyncCallbackQueue()<br>  // → ONE call to ensureRootIsScheduled with ALL three updates<br>}<br><br>// Without batching:<br>function withoutBatching() {<br>  setState(1);  // Schedule immediately → Task 1 in queue<br>  setState(2);  // Schedule immediately → Task 2 in queue<br>  setState(3);  // Schedule immediately → Task 3 in queue<br>  // Three separate reconciliation passes!<br>}</pre><p>React 18’s Automatic Batching:</p><pre>// React 18 extends batching everywhere using microtasks<br>function ensureRootIsScheduled(root, lane) {<br>  // ... determine priority ...<br><br>  if (lane === SyncLane) {<br>    scheduleSyncCallback(performSyncWorkOnRoot);<br>    <br>    // Magic: Schedule flush in microtask queue<br>    if (executionContext === NoContext) {<br>      queueMicrotask(() =&gt; flushSyncCallbacks());<br>    }<br>  }<br>}<br><br>// Now even this batches:<br>setTimeout(() =&gt; {<br>  setState(1);  // Queued<br>  setState(2);  // Queued<br>  setState(3);  // Queued<br>  // setTimeout callback completes<br>  // → Microtask queue processes<br>  // → flushSyncCallbacks() runs<br>  // → ONE reconciliation<br>}, 1000);</pre><h3>System 3: The Scheduling Bridge</h3><p>This is <strong>how the task queue gets populated</strong></p><pre>// The bridge from Fiber to Scheduler<br>function ensureRootIsScheduled(root: FiberRoot, lane: Lane) {<br>  // Step 1: Mark work on the root<br>  root.pendingLanes |= lane;<br><br>  // Step 2: Determine scheduler priority from React lane<br>  const schedulerPriority = lanesToSchedulerPriority(lane);<br><br>  // Step 3: THIS IS WHERE TASK QUEUE GETS POPULATED<br>  const callback = performConcurrentWorkOnRoot.bind(null, root);<br>  <br>  scheduleCallback(schedulerPriority, callback);<br>  // ↑ This is your PriorityScheduler.scheduleCallback from the article<br>}<br><br>// Convert React&#39;s lane system to Scheduler&#39;s priority system<br>function lanesToSchedulerPriority(lanes: Lanes): SchedulerPriority {<br>  // Find highest priority lane<br>  if (lanes &amp; SyncLane) return ImmediatePriority;           // -1ms timeout<br>  if (lanes &amp; InputContinuousLane) return UserBlockingPriority;  // 250ms<br>  if (lanes &amp; DefaultLane) return NormalPriority;            // 5000ms<br>  if (lanes &amp; TransitionLanes) return NormalPriority;        // 5000ms<br>  if (lanes &amp; IdleLane) return IdlePriority;                // Never expires<br>  <br>  return NormalPriority;<br>}<br><br>// Inside your Scheduler (from the article)<br>class PriorityScheduler {<br>  scheduleCallback(priority: Priority, callback: Function): Task {<br>    const currentTime = performance.now();<br>    const timeout = this.timeoutForPriority(priority);<br>    const expirationTime = currentTime + timeout;<br><br>    // Create task object<br>    const task: Task = {<br>      id: this.taskIdCounter++,<br>      callback: callback,           // performConcurrentWorkOnRoot<br>      priority: priority,<br>      expirationTime: expirationTime,<br>      sortIndex: expirationTime<br>    };<br><br>    // THIS IS THE ANSWER: Task queue gets populated here<br>    this.push(this.taskQueue, task);  // Add to min-heap<br><br>    // Start processing if not already running<br>    if (!this.isPerformingWork) {<br>      this.requestHostCallback(this.flushWork);<br>    }<br><br>    return task;<br>  }<br>}</pre><p>Lane Propagation — Why It Matters:</p><pre>// Before scheduling, lanes must propagate up the tree<br>function markUpdateLaneFromFiberToRoot(fiber: FiberNode, lane: Lane): FiberRoot {<br>  // Mark the fiber that has the update<br>  fiber.lanes = mergeLanes(fiber.lanes, lane);<br><br>  // Walk up, marking all ancestors&#39; childLanes<br>  let parent = fiber.return;<br>  while (parent !== null) {<br>    parent.childLanes = mergeLanes(parent.childLanes, lane);<br>    parent = parent.return;<br>  }<br><br>  return getRootForFiber(fiber);<br>}<br><br>// Why? During reconciliation, React can skip subtrees:<br>function beginWork(fiber, renderLanes) {<br>  // If this fiber&#39;s childLanes don&#39;t overlap with what we&#39;re rendering,<br>  // skip the entire subtree - no work here!<br>  if ((fiber.childLanes &amp; renderLanes) === NoLanes) {<br>    return null;  // Bailout<br>  }<br><br>  // Has work, continue reconciling<br>  // ...<br>}</pre><h3>System 4: The Reconciliation Process</h3><p>Now the scheduler executes the task, triggering reconciliation:</p><pre>// Scheduler&#39;s work loop picks up the task<br>workLoop(deadline: IdleDeadline) {<br>  while (this.currentTask !== null &amp;&amp; deadline.timeRemaining() &gt; 0) {<br>    const callback = this.currentTask.callback;<br>    <br>    // Execute: performConcurrentWorkOnRoot(root)<br>    const continuationCallback = callback();<br>    <br>    if (continuationCallback) {<br>      // Work wants to continue (was interrupted)<br>      this.currentTask.callback = continuationCallback;<br>    } else {<br>      // Work complete<br>      this.pop(this.taskQueue);<br>    }<br>    <br>    this.currentTask = this.peek(this.taskQueue);<br>  }<br>}<br><br>// The reconciliation function<br>function performConcurrentWorkOnRoot(root: FiberRoot) {<br>  // Determine which lanes to render<br>  const lanes = getNextLanes(root, root.pendingLanes);<br>  <br>  // RENDER PHASE: Build work-in-progress tree<br>  renderRootConcurrent(root, lanes);<br>  <br>  // COMMIT PHASE: Apply changes to DOM<br>  if (workInProgressRootExitStatus === RootCompleted) {<br>    commitRoot(root);<br>  }<br>}<br><br>// The actual reconciliation loop<br>function renderRootConcurrent(root: FiberRoot, lanes: Lanes) {<br>  // Start at root<br>  let workInProgress = root.current.alternate;<br>  <br>  while (workInProgress !== null) {<br>    // Process this fiber<br>    workInProgress = performUnitOfWork(workInProgress);<br>    <br>    // Should we pause? Check priorities<br>    if (shouldYield()) {<br>      // Higher priority work arrived, pause here<br>      return RootIncomplete;<br>    }<br>  }<br>  <br>  return RootCompleted;<br>}<br><br>// Process one fiber node<br>function performUnitOfWork(fiber: FiberNode): FiberNode | null {<br>  // STEP 1: Process updates from updateQueue<br>  if (fiber.updateQueue !== null) {<br>    processUpdateQueue(fiber);<br>  }<br><br>  // STEP 2: Render component<br>  let nextChildren;<br>  if (fiber.tag === FunctionComponent) {<br>    const Component = fiber.type;<br>    nextChildren = Component(fiber.memoizedProps);<br>  }<br><br>  // STEP 3: Reconcile children (diff Virtual DOM)<br>  reconcileChildren(fiber, nextChildren);<br><br>  // STEP 4: Return next unit of work<br>  if (fiber.child !== null) {<br>    return fiber.child;  // Go down<br>  }<br>  <br>  // No children, go to sibling or up<br>  let node = fiber;<br>  while (node !== null) {<br>    completeWork(node);  // Mark effects<br>    <br>    if (node.sibling !== null) {<br>      return node.sibling;  // Go to sibling<br>    }<br>    <br>    node = node.return;  // Go up<br>  }<br>  <br>  return null;  // Tree complete<br>}<br><br>// Process the accumulated updates<br>function processUpdateQueue(fiber: FiberNode) {<br>  const queue = fiber.updateQueue;<br>  let firstUpdate = queue.shared.pending;<br>  <br>  if (firstUpdate === null) return;<br>  <br>  // Break circular list<br>  const lastUpdate = firstUpdate;<br>  const firstUpdateInQueue = lastUpdate.next;<br>  lastUpdate.next = null;<br>  <br>  // Apply each update<br>  let newState = queue.baseState;<br>  let update = firstUpdateInQueue;<br>  <br>  while (update !== null) {<br>    newState = getStateFromUpdate(update, newState);<br>    update = update.next;<br>  }<br>  <br>  // Store result<br>  fiber.memoizedState = newState;<br>  queue.shared.pending = null;<br>}</pre><h3>Priority and Scheduling</h3><p><strong>Fiber</strong> introduces priority-based scheduling to ensure high-priority updates (like user input) aren’t blocked by low-priority work:</p><pre>// Priority levels in React<br>enum Lane {<br>  NoLane = 0b0000000000000000000000000000000,<br>  SyncLane = 0b0000000000000000000000000000001,<br>  InputContinuousLane = 0b0000000000000000000000000000100,<br>  DefaultLane = 0b0000000000000000000000000010000,<br>  TransitionLane1 = 0b0000000000000000000000001000000,<br>  TransitionLane2 = 0b0000000000000000000000010000000,<br>  IdleLane = 0b0100000000000000000000000000000,<br>  OffscreenLane = 0b1000000000000000000000000000000,<br>}<br><br>// Priority scheduler<br>class PriorityScheduler {<br>  private taskQueue: Task[] = [];<br>  private timerQueue: Task[] = [];<br>  private currentTask: Task | null = null;<br>  private isPerformingWork = false;<br><br>  scheduleCallback(priority: Priority, callback: () =&gt; void, options?: { delay?: number }): Task {<br>    const currentTime = performance.now();<br>    const startTime = currentTime + (options?.delay || 0);<br><br>    // Calculate timeout based on priority<br>    const timeout = this.timeoutForPriority(priority);<br>    const expirationTime = startTime + timeout;<br><br>    const task: Task = {<br>      id: this.nextTaskId++,<br>      callback,<br>      priority,<br>      startTime,<br>      expirationTime,<br>      sortIndex: -1,<br>    };<br><br>    if (startTime &gt; currentTime) {<br>      // Delayed task<br>      task.sortIndex = startTime;<br>      this.push(this.timerQueue, task);<br><br>      if (this.taskQueue.length === 0 &amp;&amp; task === this.peek(this.timerQueue)) {<br>        this.requestHostTimeout(this.handleTimeout, startTime - currentTime);<br>      }<br>    } else {<br>      // Immediate task<br>      task.sortIndex = expirationTime;<br>      this.push(this.taskQueue, task);<br><br>      if (!this.isPerformingWork) {<br>        this.isPerformingWork = true;<br>        this.requestHostCallback(this.flushWork);<br>      }<br>    }<br><br>    return task;<br>  }<br><br>  private timeoutForPriority(priority: Priority): number {<br>    switch (priority) {<br>      case Priority.Immediate:<br>        return -1; // IMMEDIATE_PRIORITY_TIMEOUT<br>      case Priority.UserBlocking:<br>        return 250; // USER_BLOCKING_PRIORITY_TIMEOUT<br>      case Priority.Normal:<br>        return 5000; // NORMAL_PRIORITY_TIMEOUT<br>      case Priority.Low:<br>        return 10000; // LOW_PRIORITY_TIMEOUT<br>      case Priority.Idle:<br>        return 1073741823; // IDLE_PRIORITY_TIMEOUT (never expires)<br>      default:<br>        return 5000;<br>    }<br>  }<br><br>  private flushWork(hasTimeRemaining: boolean, initialTime: number): boolean {<br>    this.isPerformingWork = true;<br><br>    try {<br>      return this.workLoop(hasTimeRemaining, initialTime);<br>    } finally {<br>      this.currentTask = null;<br>      this.isPerformingWork = false;<br>    }<br>  }<br><br>  private workLoop(hasTimeRemaining: boolean, initialTime: number): boolean {<br>    let currentTime = initialTime;<br>    this.advanceTimers(currentTime);<br><br>    this.currentTask = this.peek(this.taskQueue);<br><br>    while (this.currentTask !== null) {<br>      if (<br>        this.currentTask.expirationTime &gt; currentTime &amp;&amp;<br>        (!hasTimeRemaining || this.shouldYieldToHost())<br>      ) {<br>        // This task hasn&#39;t expired, and we&#39;ve run out of time<br>        break;<br>      }<br><br>      const callback = this.currentTask.callback;<br><br>      if (typeof callback === &#39;function&#39;) {<br>        this.currentTask.callback = null;<br>        const continuationCallback = callback();<br><br>        if (typeof continuationCallback === &#39;function&#39;) {<br>          // Task wants to continue<br>          this.currentTask.callback = continuationCallback;<br>        } else {<br>          // Task complete<br>          if (this.currentTask === this.peek(this.taskQueue)) {<br>            this.pop(this.taskQueue);<br>          }<br>        }<br>      } else {<br>        this.pop(this.taskQueue);<br>      }<br><br>      this.currentTask = this.peek(this.taskQueue);<br>      currentTime = performance.now();<br>    }<br><br>    // Return whether there&#39;s more work<br>    return this.currentTask !== null;<br>  }<br><br>  private shouldYieldToHost(): boolean {<br>    const currentTime = performance.now();<br>    return currentTime &gt;= this.deadline;<br>  }<br><br>  // Min-heap operations for priority queue<br>  private push(heap: Task[], task: Task): void {<br>    const index = heap.length;<br>    heap.push(task);<br>    this.siftUp(heap, task, index);<br>  }<br><br>  private peek(heap: Task[]): Task | null {<br>    return heap.length === 0 ? null : heap[0];<br>  }<br><br>  private pop(heap: Task[]): Task | null {<br>    if (heap.length === 0) return null;<br><br>    const first = heap[0];<br>    const last = heap.pop()!;<br><br>    if (last !== first) {<br>      heap[0] = last;<br>      this.siftDown(heap, last, 0);<br>    }<br><br>    return first;<br>  }<br>}</pre><h3>Concurrent Mode Features</h3><p>Concurrent Mode leverages Fiber’s architecture to enable powerful features:</p><pre>// Time Slicing Example<br>function TimeSlicingDemo() {<br>  const [isPending, startTransition] = useTransition();<br>  const [inputValue, setInputValue] = useState(&#39;&#39;);<br>  const [list, setList] = useState&lt;string[]&gt;([]);<br><br>  const handleChange = (e: React.ChangeEvent&lt;HTMLInputElement&gt;) =&gt; {<br>    // High priority - immediate update<br>    setInputValue(e.target.value);<br><br>    // Low priority - can be interrupted<br>    startTransition(() =&gt; {<br>      const newList = [];<br>      for (let i = 0; i &lt; 20000; i++) {<br>        newList.push(e.target.value);<br>      }<br>      setList(newList);<br>    });<br>  };<br><br>  return (<br>    &lt;div&gt;<br>      &lt;input value={inputValue} onChange={handleChange} /&gt;<br>      {isPending &amp;&amp; &lt;span&gt;Updating list...&lt;/span&gt;}<br>      &lt;ul&gt;<br>        {list.map((item, index) =&gt; (<br>          &lt;li key={index}&gt;{item}&lt;/li&gt;<br>        ))}<br>      &lt;/ul&gt;<br>    &lt;/div&gt;<br>  );<br>}<br><br>// Suspense with Fiber<br>function SuspenseWithFiber() {<br>  // Fiber can pause rendering when a promise is thrown<br>  return (<br>    &lt;Suspense fallback={&lt;Loading /&gt;}&gt;<br>      &lt;AsyncComponent /&gt;<br>    &lt;/Suspense&gt;<br>  );<br>}<br><br>function AsyncComponent() {<br>  const data = use(fetchData()); // Throws promise if not ready<br><br>  // Fiber will:<br>  // 1. Catch the promise<br>  // 2. Show fallback<br>  // 3. Resume rendering when promise resolves<br>  return &lt;div&gt;{data}&lt;/div&gt;;<br>}</pre><h3>How Fiber Impacts Performance</h3><h4>Batching and Auto-batching</h4><pre>// React 18+ automatic batching<br>function AutoBatchingExample() {<br>  const [count, setCount] = useState(0);<br>  const [flag, setFlag] = useState(false);<br><br>  // Before React 18: 2 renders<br>  // React 18+: 1 render (automatic batching)<br>  const handleClick = () =&gt; {<br>    setCount((c) =&gt; c + 1);<br>    setFlag((f) =&gt; !f);<br>    // Both updates batched automatically<br>  };<br><br>  // Even in async code!<br>  const handleAsyncClick = async () =&gt; {<br>    const data = await fetchData();<br><br>    // Still batched in React 18+<br>    setCount(data.count);<br>    setFlag(data.flag);<br>  };<br><br>  // Opt out of batching when needed<br>  const handleImmediateUpdate = () =&gt; {<br>    flushSync(() =&gt; {<br>      setCount((c) =&gt; c + 1);<br>    }); // Forces immediate render<br><br>    // This runs after count is updated<br>    setFlag((f) =&gt; !f);<br>  };<br><br>  return (<br>    &lt;div&gt;<br>      &lt;p&gt;Count: {count}, Flag: {flag.toString()}&lt;/p&gt;<br>      &lt;button onClick={handleClick}&gt;Update Both&lt;/button&gt;<br>    &lt;/div&gt;<br>  );<br>}</pre><h3>Optimizing for Fiber’s Algorithm</h3><pre>// Component structured for Fiber optimization<br>function FiberOptimizedComponent({ data }: { data: Item[] }) {<br>  // 1. Stable keys for efficient reconciliation<br>  const items = useMemo(<br>    () =&gt;<br>      data.map((item) =&gt; ({<br>        ...item,<br>        key: item.id, // Stable key<br>      })),<br>    [data],<br>  );<br><br>  // 2. Priority-aware updates<br>  const [search, setSearch] = useState(&#39;&#39;);<br>  const [deferredSearch] = useDeferredValue(search);<br><br>  // 3. Interrupt-friendly expensive computation<br>  const filtered = useMemo(<br>    () =&gt; <br>      items.filter((item) =&gt; <br>        item.name.toLowerCase().includes(deferredSearch.toLowerCase())<br>      ),<br>    [items, deferredSearch],<br>  );<br><br>  // 4. Leverage suspense for data fetching<br>  return (<br>    &lt;div&gt;<br>      &lt;input<br>        value={search}<br>        onChange={(e) =&gt; setSearch(e.target.value)}<br>        placeholder=&quot;Search (high priority)&quot;<br>      /&gt;<br><br>      &lt;Suspense fallback={&lt;Skeleton /&gt;}&gt;<br>        &lt;ItemList items={filtered} /&gt;<br>      &lt;/Suspense&gt;<br>    &lt;/div&gt;<br>  );<br>}<br><br>// Understanding bailout optimization<br>function BailoutOptimization({ value }: { value: number }) {<br>  console.log(&#39;Parent render&#39;);<br><br>  // Fiber can skip rendering children if props haven&#39;t changed<br>  return (<br>    &lt;&gt;<br>      &lt;ExpensiveChild /&gt; {/* Skipped if no props change */}<br>      &lt;CheapChild value={value} /&gt;<br>    &lt;/&gt;<br>  );<br>}<br><br>const ExpensiveChild = memo(() =&gt; {<br>  console.log(&#39;ExpensiveChild render&#39;);<br>  // Complex computation...<br>  return &lt;div&gt;Expensive&lt;/div&gt;;<br>});</pre><h3>Debugging Fiber Internals</h3><pre>// Accessing Fiber internals (development only)<br>function FiberDebugger({ children }: { children: React.ReactNode }) {<br>  const ref = useRef&lt;HTMLDivElement&gt;(null);<br><br>  useEffect(() =&gt; {<br>    if (process.env.NODE_ENV === &#39;development&#39;) {<br>      // Access fiber node<br>      const fiberNode =<br>        (ref.current as any)?._reactInternalFiber || (ref.current as any)?._reactInternalInstance;<br><br>      if (fiberNode) {<br>        console.group(&#39;Fiber Node Structure&#39;);<br>        console.log(&#39;Type:&#39;, fiberNode.type);<br>        console.log(&#39;Tag:&#39;, fiberNode.tag);<br>        console.log(&#39;Props:&#39;, fiberNode.memoizedProps);<br>        console.log(&#39;State:&#39;, fiberNode.memoizedState);<br>        console.log(&#39;Effects:&#39;, fiberNode.flags);<br>        console.log(&#39;Priority:&#39;, fiberNode.lanes);<br>        console.groupEnd();<br><br>        // Traverse fiber tree<br>        traverseFiberTree(fiberNode);<br>      }<br>    }<br>  }, []);<br><br>  return &lt;div ref={ref}&gt;{children}&lt;/div&gt;;<br>}<br><br>function traverseFiberTree(fiber: any, depth = 0) {<br>  const indent = &#39;  &#39;.repeat(depth);<br>  console.log(`${indent}${fiber.type?.name || fiber.type || &#39;Unknown&#39;}`);<br><br>  // Traverse children<br>  let child = fiber.child;<br>  while (child) {<br>    traverseFiberTree(child, depth + 1);<br>    child = child.sibling;<br>  }<br>}<br><br>// Performance marks for Fiber phases<br>function measureFiberPhases() {<br>  if (typeof window !== &#39;undefined&#39; &amp;&amp; window.performance) {<br>    // React adds marks during rendering<br>    const marks = performance.getEntriesByType(&#39;mark&#39;);<br>    const reactMarks = marks.filter(<br>      (mark) =&gt; mark.name.startsWith(&#39;⚛&#39;) || mark.name.includes(&#39;React&#39;),<br>    );<br><br>    console.table(<br>      reactMarks.map((mark) =&gt; ({<br>        name: mark.name,<br>        startTime: mark.startTime,<br>        duration: mark.duration,<br>      })),<br>    );<br>  }<br>}</pre><h3>Practical Fiber Optimizations</h3><pre>// 1. Structure components for efficient reconciliation<br>function EfficientList({ items }: { items: Item[] }) {<br>  return (<br>    &lt;div&gt;<br>      {items.map((item) =&gt; (<br>        // Stable key = efficient reconciliation<br>        &lt;Item key={item.id} {...item} /&gt;<br>      ))}<br>    &lt;/div&gt;<br>  );<br>}<br><br>// 2. Use lanes for priority<br>function PriorityAwareComponent() {<br>  const [urgent, setUrgent] = useState(&#39;&#39;);<br>  const [deferred, setDeferred] = useState(&#39;&#39;);<br><br>  return (<br>    &lt;div&gt;<br>      &lt;input<br>        value={urgent}<br>        onChange={(e) =&gt; {<br>          // Sync lane - highest priority<br>          setUrgent(e.target.value);<br>        }}<br>      /&gt;<br><br>      &lt;button<br>        onClick={() =&gt; {<br>          // Transition lane - lower priority<br>          startTransition(() =&gt; {<br>            setDeferred(processData(urgent));<br>          });<br>        }}<br>      &gt;<br>        Process<br>      &lt;/button&gt;<br>    &lt;/div&gt;<br>  );<br>}<br><br>// 3. Minimize fiber tree depth<br>// ❌ Deep nesting = more fiber nodes<br>function DeepNesting() {<br>  return (<br>    &lt;div&gt;<br>      &lt;div&gt;<br>        &lt;div&gt;<br>          &lt;div&gt;<br>            &lt;Content /&gt;<br>          &lt;/div&gt;<br>        &lt;/div&gt;<br>      &lt;/div&gt;<br>    &lt;/div&gt;<br>  );<br>}<br><br>// ✅ Flat structure = fewer fiber nodes<br>function FlatStructure() {<br>  return (<br>    &lt;div className=&quot;container&quot;&gt;<br>      &lt;Content /&gt;<br>    &lt;/div&gt;<br>  );<br>}<br><br>// 4. Leverage Suspense boundaries<br>function SuspenseBoundaries() {<br>  return (<br>    &lt;div&gt;<br>      {/* Each boundary can work independently */}<br>      &lt;Suspense fallback={&lt;HeaderSkeleton /&gt;}&gt;<br>        &lt;Header /&gt;<br>      &lt;/Suspense&gt;<br><br>      &lt;Suspense fallback={&lt;ContentSkeleton /&gt;}&gt;<br>        &lt;Content /&gt;<br>      &lt;/Suspense&gt;<br><br>      &lt;Suspense fallback={&lt;SidebarSkeleton /&gt;}&gt;<br>        &lt;Sidebar /&gt;<br>      &lt;/Suspense&gt;<br>    &lt;/div&gt;<br>  );<br>}</pre><h3>Wrapping Up</h3><p>The Virtual DOM and Fiber architecture are the beating heart of React’s performance story. The Virtual DOM provides the declarative programming model we love, while Fiber transforms that model into an efficient, interruptible, priority-aware rendering machine. Understanding these internals isn’t just academic — it directly informs how you structure components, manage state, and optimize performance.</p><p><strong>The key insights:</strong> React can interrupt and resume work, different updates have different priorities, and the reconciliation algorithm rewards stable keys and shallow component trees. Write your React code with these principles in mind, and you’re working with the framework’s natural grain rather than against it.</p><p>Master Fiber’s mental model, and you’ll write React applications that aren’t just fast — they’re predictably fast, gracefully handling everything from smooth animations to massive lists without breaking a sweat.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=1619721ae96f" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[Write your Own useState Hook from scratch.]]></title>
            <link>https://medium.com/@bikid475/write-your-own-usestate-hook-from-scratch-231566d83b89?source=rss-3ac124cb043------2</link>
            <guid isPermaLink="false">https://medium.com/p/231566d83b89</guid>
            <category><![CDATA[web-developement]]></category>
            <category><![CDATA[javascript]]></category>
            <category><![CDATA[react]]></category>
            <category><![CDATA[functional-programming]]></category>
            <dc:creator><![CDATA[Biki Das]]></dc:creator>
            <pubDate>Thu, 26 Sep 2024 08:23:25 GMT</pubDate>
            <atom:updated>2026-02-21T18:11:35.377Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="" src="https://cdn-images-1.medium.com/max/454/1*u_RCiIVTG0XnIViJvbBCMA.png" /></figure><p><strong>useState</strong> is the most commonly used hook one would like to reach out in React for doing state Management, In this Article, we would try to write our own useState hook and understand how it works under the hood. This is just for educational purpose, In real life circumstances we should not try to do custom implementation of things which already exist unless there is a specific constraint.</p><p>Let start by Drafting the Structure of <strong>useState</strong></p><pre>function useState(initivalValue) {<br>   // need to do something that helps us do re-renders<br>   // return use the currentStateValue and state Updater function<br>}</pre><p>So how we can go about solving this? When it comes to React there is a <strong>useReducer </strong>method, which helps us Separate our state Update logic and applies a reducer pattern to modify states. now why do we need to use <strong>useReducer </strong>to build a <strong>useState </strong>hook, we will see it later, lets start writing the logic for our <strong>useState.</strong></p><pre>import { useRef } from &quot;react&quot;;<br><br>function useState(initivalValue) {<br>   const stateRef = useRef(initialValue); <br>   <br>   // remaining Main logic<br>}</pre><p>we need to first preserve the initialValue such that it does not get changed in any case, refs are best way to preserve values, now as we talked about <strong>useReducer, </strong>it gives us a very powerful function called as<strong> dispatch </strong>function which can trigger re-render, like calling <strong>dispatch(), </strong>is like saying to react to trigger render and update our DOM. Even <strong>useState </strong>under the hood uses the same method to trigger the re-render. so lets complete our <strong>useStateHook</strong></p><pre><br>import { useRef,useReducer } from &quot;react&quot;;<br><br>function useState(initivalValue) {<br>   const stateRef = useRef(initialValue); <br>   const [_,forceRender] = useReducer((b) =&gt; !b,false)<br>}</pre><p>now we have used the <strong>useReducer </strong>hook, it takes a reducer callback and an initial Value similar to our <strong>Reducer </strong>function available on Array prototype, what we do inside the callback in our context is not important, as we just want to safely retrieve the <strong>dispatch </strong>method which we are calling <strong>forceRender. </strong>Now the only thing left to do is making our <strong>StateUpdater</strong> method and returning our state value and its <strong>UpdaterMethod. </strong>Lets complete it.</p><pre>import { useRef, useReducer } from &quot;react&quot;;<br><br>export function useState(initialValue) {<br>  const stateRef = useRef(initialValue);<br>  const [, forceRender] = useReducer((b) =&gt; !b, false);<br><br>  const setState = (newValue) =&gt; {<br>      stateRef.current = newValue;<br>      forceRender();<br>  };<br><br>  return [stateRef.current, setState];<br>}</pre><p>The<strong> SetState </strong>method is pretty straight forward, it takes the newValue as the argument and replaces our stateRef Value with the same and then eventually call the <strong>forceRender() </strong>method and eventually Return the <strong>stateValue</strong> and <strong>stateUpdaterFunction.</strong></p><p>We are almost there, but there is a slight issue in our <strong>useState </strong>hook as of now, and let me explain the issue, in React when we use <strong>useState, </strong>it only triggers the re-render, if the previousStateValue and currentStateValue differs.</p><pre>import {useState} from &#39;react&#39;<br><br>const App = () =&gt; {<br>  const [count,setCount] = useState(0)<br><br>  function IncrementCount() {<br>      setCount(0) // This won&#39;t trigger re-render<br>   }<br><br>  return(<br>     &lt;&gt;<br>      &lt;p&gt;{count}&lt;/p&gt;<br>      &lt;button onClick={IncrementCount}&gt;increment&lt;/button&gt;<br>    &lt;/&gt;<br>   )<br><br>}</pre><p>But if we try to see our own <strong>useState </strong>hook, this is not the case</p><pre>import { useRef, useReducer } from &quot;react&quot;;<br><br>export function useState(initialValue) {<br>  const stateRef = useRef(initialValue);<br>  const [, forceRender] = useReducer((b) =&gt; !b, false);<br><br>  const setState = (newValue) =&gt; {<br>      stateRef.current = newValue;<br>      forceRender();<br>  };<br><br>  return [stateRef.current, setState];<br>}</pre><p>whenever we are calling the <strong>SetState, </strong>we just directly update the value and call the <strong>forceRender </strong>which is not correct, and the fix is pretty simple and something which even React under the hood uses, we can try to compare the two Values whether both are equal and we would use the <strong>Object.is </strong>method over our <strong>StateRef </strong>value and <strong>newValue </strong>to determine the same, and only if the result of calling <strong>Object.is </strong>is false, we would set our stateRef to our newValue and force Re-render.</p><pre>import { useRef, useReducer } from &quot;react&quot;;<br><br>export function useState(initialValue) {<br>  const stateRef = useRef(initialValue);<br>  const [, forceRender] = useReducer((b) =&gt; !b, false);<br><br>  const setState = (newValue) =&gt; {<br>    if (Object.is(stateRef.current, newValue) === false) {<br>      stateRef.current = newValue;<br>      forceRender();<br>    }<br>  };<br><br>  return [stateRef.current, setState];<br>}</pre><p>now this actually completes our implementation of our useState Hook, in practice there are lot of things React does with <strong>useState </strong>which simply out of my understanding, but this can give you a better mental model of what useState does under the hood, The amazing part about all of this is React is not doing any magic under the hood, its using already existing JavaScript patterns to simplify how we write and think about UI. That’s it for this article, Hope you enjoyed reading this.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=231566d83b89" width="1" height="1" alt="">]]></content:encoded>
        </item>
        <item>
            <title><![CDATA[How Passing Elements as Props in React can benefit Performance?]]></title>
            <link>https://medium.com/@bikid475/how-passing-elements-as-props-in-react-can-benefit-performance-c6d00b3c924d?source=rss-3ac124cb043------2</link>
            <guid isPermaLink="false">https://medium.com/p/c6d00b3c924d</guid>
            <category><![CDATA[javacript]]></category>
            <category><![CDATA[functional-programming]]></category>
            <category><![CDATA[react]]></category>
            <dc:creator><![CDATA[Biki Das]]></dc:creator>
            <pubDate>Sun, 01 Sep 2024 07:16:46 GMT</pubDate>
            <atom:updated>2024-09-01T08:24:44.927Z</atom:updated>
            <content:encoded><![CDATA[<figure><img alt="React Element Illustration" src="https://cdn-images-1.medium.com/max/575/1*hLSi-An9G9av9OcNV_wMgQ.png" /><figcaption>Elements being passed as Props and being consumed</figcaption></figure><p>In React, re-renders are the only way your React components get updated with the Latest Data, without re-renders, your app is static. we are going to understand how passing Elements as Props in React helps us with performance, Before diving into the topic of this Blog, let us understand two crucial terms we need to have good understanding to make sense of this blog</p><p><strong>What is a React Component ?</strong></p><p>React components in a nutshell are functions, just like in JavaScript, but unlike regular functions they return us React Elements.</p><pre>function Button() {<br>  return (<br>    &lt;button&gt;Click Me&lt;/button&gt;<br>    )<br>}<br><br>// Button here is a Component</pre><p><strong>what is a React Element?</strong></p><p>Every React Component if it want to render something has to return Element, the Element can be a React component itself or a Vali<strong>d HTML DOM</strong> element, This Elements are just Plain JavaScript Objects. They have a special Syntax where they are wrapped between Angle Brackets Just like Regular DOM Elements.</p><pre>function Footer() {<br>const [date, setDate] = useState(new Date())<br>  return (<br>     &lt;&gt;<br>     {date}<br>    &lt;Button /&gt;<br>     &lt;/&gt;<br>    )<br>}<br><br>// Button is the Element Here<br>// The Footer Component can also become an Element like &lt;Footer /&gt;</pre><p>Under the Hood when React Calls a component either in case of initial render or re-rendering, the component call returns the Object as we discussed above, which React would use to generate a tree of these Objects, this is what is referred to as the Virtual DOM, in case of subsequent Renders, React generates Two trees, <strong>Before Render</strong> and <strong>After Render.</strong></p><p>if you try to paste any Component inside Babel Playground, you will get to see internally the returned Values, are Just Plain <strong>React.createElement</strong> calls in our case it would look like<strong> React.createElement(“Button”, null, null)</strong></p><p>Under the Hood when React Calls a component either in case of initial render or re-rendering, the component call returns the Object as we discussed above, which React would use to generate a tree of these Objects, this is what is referred to as the <strong>Virtual DOM</strong>, in case of subsequent Renders, React generates Two trees, <strong>Before Render</strong> and <strong>After Render.</strong></p><p>To perform reconciliation, React would compare these two tree to seek information it would apply to the DOM to add, delete or update the DOM as it requires. The Objects returned eventually becomes what we see on the Screen and the Object has a special Structure Like Below</p><pre>{<br> type: &quot;Button&quot;,<br> props : {},<br> // More Internal Stuff Used by React<br>}</pre><p>Now let us see what would happen during reconciliation when we call our Footer Component, the whole Footer component runs, the state is instantiated, once we reach the Button Element, React will run the diffing process, calling <strong>Object.is</strong> over <strong>beforeRender</strong> and <strong>AfterRender</strong>, in this case every time in memory a new Object is generated for the Button Element, which means the comparison will result in <strong>False</strong>, which signals react to re-render as something has changed.</p><pre>function Footer() {<br>const [date, setDate] = useState(new Date())<br>  return (<br>     &lt;&gt;<br>     {date}<br>    &lt;Button /&gt;<br>     &lt;/&gt;<br>    )<br>}<br></pre><p>if the <strong>type</strong> key as we see above has not changed, it will just re-render the component with the new attributes as required, however if the type has changed it means it needs to delete the existing DOM attached to it and mount the new one.</p><p>Time to unwrap the central agenda of this Blog how passing the Element as Props can help us with Performance, now lets change something</p><pre>function Footer({Button}) {<br>const [date, setDate] = useState(new Date())<br>  return (<br>     &lt;&gt;<br>     {date}<br>    &lt;Button /&gt;<br>     &lt;/&gt;<br>    )<br>}<br><br>// Somewhere Above the Code<br><br>&lt;Footer Button={Button}/&gt;</pre><p>Let us run through the Whole reconciliation process once more, this time we are passing the Button from outside the<strong> Footer</strong> component, as a reference, so when the <strong>Diffing process </strong>runs, state is instantiated, and then calling <strong>Object.is</strong> called over the <strong>beforeRender</strong> and <strong>afterRender </strong>on the returned value, this time the Button Object is created outside the <strong>Footer</strong> function scope, and so it won’t change when Footer gets called, which results the expression in <strong>True</strong>, which signal react to skip re-render of this component.</p><p>This was a very simple example, but it is a very powerful technique in my opinion when you just can’t simply lift the state down to minimise re-renders to achieve performance, though passing elements as Props might feel weird and invalid, so React has another special syntax which does the same thing.</p><pre>function Footer({children}) {<br>const [date, setDate] = useState(new Date())<br>  return (<br>     &lt;&gt;<br>     {date}<br>     {children}<br>     &lt;/&gt;<br>    )<br>}<br><br>// Somewhere Above the Code<br><br>&lt;Footer&gt;<br> &lt;Button/&gt;<br>&lt;Footer/&gt;</pre><p>In the Above code now, we are using a special reserved prop called children which allow us to pass React Elements explicitly in a nested manner, this is a better syntax in my opinion, and we get the same performance benefits as we saw, this is just a syntactic sugar.</p><pre>&lt;Footer Button={Button}/&gt;<br><br>// The above is same as Below<br><br>&lt;Footer&gt;<br>&lt;Button/&gt;<br>&lt;/Footer&gt;</pre><p>I hope i was able to explain the performance benefits of passing Elements as Props, its more related to how JavaScript works, if you have doubts regarding the same feel free to comment your doubt, i will come up with More React related internal blogs.</p><p>Thanks for Reading.</p><img src="https://medium.com/_/stat?event=post.clientViewed&referrerSource=full_rss&postId=c6d00b3c924d" width="1" height="1" alt="">]]></content:encoded>
        </item>
    </channel>
</rss>