SoFunction
Updated on 2025-04-04

Comprehensive and in-depth analysis of the core principles of React framework

Preface

This article introduces the following concepts step by step. Following the principles of this article, you can basically understand why fiber is needed, why commit, phases, reconciliation stages and other principles. This article is not exactly consistent with the original text. I will add some of my own thoughts here, such asperformUnitOfWorkAfter processing, the connection between fiber tree and element tree, etc.

  • createElement function
  • render function
  • Concurrent Mode
  • Fibers
  • Render and Commit Phases
  • Reconciliation
  • Function Components
  • Hooks

Chapter 1 Basic Concept

The following code is an example

// Syntax is not a legal js syntax// const element = <h1 title="foo">Hello</h1>
// 2. The way to convert jsx to js through babel and other compilation tools, and convert jsx to createElement function call// const element = (
//   "h1",
//   { title: "foo" },
//   "Hello"
// )
// The final object returned is roughly as follows:const element = {
  type: "h1",
  props: {
    title: "foo",
    children: "Hello",
  },
}
const container = ("root")
// (element, container)
// 4. Replace the logic of the function, roughly handle the logic:const node = ()
node['title'] = 
const text = ("")
text["nodeValue"] = 
(text)
(node)

To avoid ambiguity, hereelementexpressReact elementsnodeRepresents the real DOM element node.

At this point, this code can run on the browser without any compilation. If you don't believe it, you can copy it to the browser console to try it.

Here are a few points to note:

  • Pass first(text)Add child elements to parent element and then pass(node)Add parent element to containercontainerTriggers the browser rendering page. This order cannot be reversed, which means that only if the entire real dom tree is built, it can be added to the container. Assume that the order is reversed, for example, execute first(node), triggers browser reflow. Execute again(text)It triggers browser reflow. Extremely poor performance
  • The final object returned isvirtual domTree,According to thisvirtual domCreate a real dom tree

Chapter 2 createElement function

The following code is an example

The received children may be an atomic value, such as a string or a number,('h1', {title: 'foo'}, 'Hello'). To simplify our code, create a specialTEXT_ELEMENTType converts it to an object

Refer to the actual video explanation of React:Enter study

 = (type, props, ...children) => {
  return {
    type,
    props: {
      ...props,
      children: (child => {
        if(typeof child === 'object'){
          return child
        }
        return {
          type: 'TEXT_ELEMENT',
          props: {
            nodeValue: child,
            children: [],
          }
        }
      })
    }
  }
}
// const element = (
//   <div >
//     <a>bar</a>
//     <b />
//   </div>
// )
// Convert jsx to js syntaxconst element = (
  "div",
  { id: "foo" },
  ("a", null, "bar"),
  ("b")
)
const container = ("root")
(element, container)

OK, now we have implemented a simple onecreateElementFunction, we can tell babel to use our own when converting jsx to jscreateElementfunction:

const MiniReact = {
  createElement:  (type, props, ...children) => {
    return {
      type,
      props: {
        ...props,
        children: (child => {
          if(typeof child === 'object'){
            return child
          }
          return {
            type: 'TEXT_ELEMENT',
            props: {
              nodeValue: child,
              children: [],
            }
          }
        })
      }
    }
  }
}
/** @jsx  */
const element = (
  <div >
    <a>bar</a>
    <b />
  </div>
)
('element======', element)
const container = ("root")
(element, container)

Chapter 3 render function

import React from 'react';
function render(element, container) {
  const dom =  === 'TEXT_ELEMENT' ? ("") : ()
  const isProperty = key => key !== 'children'
  ()
    .filter(isProperty)
    .forEach(name => {
      dom[name] = [name]
    })
  (child => {
    render(child, dom)
  });
  (dom)
}
const MiniReact = {
  createElement:  (type, props, ...children) => {
    return {
      type,
      props: {
        ...props,
        children: (child => {
          if(typeof child === 'object'){
            return child
          }
          return {
            type: 'TEXT_ELEMENT',
            props: {
              nodeValue: child,
              children: [],
            }
          }
        })
      }
    }
  },
  render
}
/** @jsx  */
const element = (
  <div >
    <a>bar</a>
    <b />
  </div>
)
('element======', element)
const container = ("root")
(element, container)

renderThe function recursively creates the real dom element, then appends each element to its parent element, and finally appends the entire dom tree to the root container, and rendering is completed. Once this process begins, it cannot be interrupted in the middle until the entire application rendering is completed. This is alsoReact16Rendering process before version

Note that the page will only be displayed when the entire dom tree is append to the root container.

Chapter 4 Concurrent Mode

You can see in Chapter 3 that the current version ofrenderThe function recursively builds the dom tree, and finally appends to the root container, and the final page is rendered. There is a problem here. If the number of dom nodes is huge and the recursive level is too deep, this process is actually very time-consuming, which leads torenderThe function occupies the main thread for a long time, and the browser cannot respond to user input and other events, causing lag.

Therefore we need torenderThe process is split into small task units, and the browser is allowed to interrupt each time one unit is executed.renderProcess and execute high-priority tasks, and continue to execute them when the browser is freerenderprocess

If it is correctrequestIdleCallbackIf you are not familiar with it, you can learn about it yourself. This API is not used in real React code because there are compatibility issues. Therefore React usesscheduler packageSimulate this scheduling process

let nextUnitOfWork = null
function workLoop(deadline) {
  let shouldYield = false
  while (nextUnitOfWork && !shouldYield) {
    nextUnitOfWork = performUnitOfWork(
      nextUnitOfWork
    )
    shouldYield = () < 1
  }
  requestIdleCallback(workLoop)
}
requestIdleCallback(workLoop)
function performUnitOfWork(nextUnitOfWork) {
  // TODO
}

performUnitOfWorkReceive the current unit of work and return to the next unit of work. The work unit can be understood as a fiber object node

workLoopThe loop will be calledperformUnitOfWork, the loop terminates until all work units have been processed, or the current frame browser has no idle time. Wait until the browser is free next time before continuing to execute

Therefore, we need a data structure that can support task interruption and can continue execution. Obviously, linked lists are very suitable for

Chapter 5 Fibers

Fibers is a data structure that supports splitting the rendering process into work units, which is essentially a two-way linked list. The advantage of this data structure is that it is easy to find the next unit of work

Fiber contains three meanings:

  • As an architecture,React 15ofReconcilerExecute in recursive way, and the data is stored in the recursive call stack, so it is calledstack ReconcilerReact 16ofReconcilerBased on Fiber node implementation, it is calledFiber Reconciler
  • As a static data structure, each Fiber node corresponds to aReact Element, saves the type of the component (function component/class component/html tag), corresponding DOM node information, etc.
  • As a dynamic unit of work, each Fiber node saves the status of the component changing, the work to be performed in this update, etc.

Some cold knowledge about Fiber:

  • A Fiber node corresponds to a React Element node, and is also a unit of work
  • Each fiber node has a pointer to the first child element, the next brother element, and the parent element**

The following code is an example:

(
  <div>
    <h1>
      <p />
      <a />
    </h1>
    <h2 />
  </div>,
  container
)

The corresponding fiber tree is as follows:

import React from 'react';
// Create real dom nodes based on fiber nodesfunction createDom(fiber) {
  const dom =  === 'TEXT_ELEMENT' ? ("") : ()
  const isProperty = key =&gt; key !== 'children'
  ()
    .filter(isProperty)
    .forEach(name =&gt; {
      dom[name] = [name]
    })
  return dom
}
let nextUnitOfWork = null
// The main logic of the render function:// Create root fiber based on root container// Point nextUnitOfWork pointer to root fiber// element is react element treefunction render(element, container){
  nextUnitOfWork = {
    dom: container,
    props: {
      children: [element], // At this time, the element is just a virtual dom tree created by the function.    },
  }
}
function workLoop(deadline) {
  let shouldYield = false
  while (nextUnitOfWork &amp;&amp; !shouldYield) {
    nextUnitOfWork = performUnitOfWork(nextUnitOfWork)
    shouldYield = () &lt; 1
  }
  requestIdleCallback(workLoop)
}
requestIdleCallback(workLoop)
// The main logic of performUnitOfWork function:// Add element element to DOM// Create corresponding fiber node for element child elements// Return to the next unit of work, that is, the next fiber node, the search process:// 1. If there is a child element, return the fiber node of the child element// 2. If there are no child elements, return the fiber node of the sibling element// 3. If there are neither child elements nor sibling elements, then look up the fiber node of the sibling element of its parent node// 4. If you find the root fiber node upward, it means that the render process has endedfunction performUnitOfWork(fiber) {
  // The first step is to create a real dom node based on the fiber node and save it in the properties  if(!){
     = createDom(fiber)
  }
  // Step 2 Add the real dom of the current fiber node to the parent node. Note that this step will trigger the browser to reflow and repaint!  !  !  if(){
    ()
  }
  // Step 3 Create the corresponding fiber node for the child element  const children = 
  let prevSibling
  ((child, index) =&gt; {
    const newFiber = {
      type: ,
      props: ,
      parent: fiber,
      dom: null
    }
    if(index === 0){
       = newFiber
    } else {
       = newFiber
    }
    prevSibling = newFiber
  })
  // Step 4: Find the next unit of work  if(){
    return 
  }
  let nextFiber = fiber
  while(nextFiber){
    if(){
      return 
    }
    nextFiber = 
  }
}
const MiniReact = {
  createElement:  (type, props, ...children) =&gt; {
    return {
      type,
      props: {
        ...props,
        children: (child =&gt; {
          if(typeof child === 'object'){
            return child
          }
          return {
            type: 'TEXT_ELEMENT',
            props: {
              nodeValue: child,
              children: [],
            }
          }
        })
      }
    }
  },
  render
}
/** @jsx  */
const element = (
  &lt;div&gt;
    &lt;h1&gt;
      &lt;p /&gt;
      &lt;a /&gt;
    &lt;/h1&gt;
    &lt;h2 /&gt;
  &lt;/div&gt;
)
// const element = (
//   &lt;div &gt;
//     &lt;a&gt;bar&lt;/a&gt;
//     &lt;b /&gt;
//   &lt;/div&gt;
// )
('element======', element)
const container = ("root")
(element, container)

Here is something worth savoring.Returnedelement treeandperformUnitOfWorkCreatedfiber treeWhat are the connections? As shown in the figure below:

  • React Element TreeIs it fromTree structure object created by method
  • Fiber TreeIt is based onReact Element TreeThe tree created. Each Fiber node saves the real DOM node and saves the rightReact Element TreeCorrespondingElementApplication of nodes. Notice,ElementNodes will not be savedFiberApplication of nodes

Chapter 6 Render and Commit Phases

Chapter 5performUnitOfWorkThere are some problems. In the second step, we directly mount the newly created real dom node to the container, which will bring two problems:

  • Each executionperformUnitOfWorkIt will cause the browser to reflow and repaint, because the real dom has been added to the browser, and the performance is extremely poor.
  • The browser can interrupt the rendering process, which may cause users to see an incomplete UI interface.

We need to revise our code,performUnitOfWorkThe real dom node is not mounted to the container in the stage. Save reference to the fiber tree root node. Wait until the fiber tree build is completed, the real dom node is submitted once and added to the container.

import React from 'react';
function createDom(fiber) {
  const dom =  === 'TEXT_ELEMENT' ? ("") : ()
  const isProperty = key =&gt; key !== 'children'
  ()
    .filter(isProperty)
    .forEach(name =&gt; {
      dom[name] = [name]
    })
  return dom
}
let nextUnitOfWork = null
let wipRoot = null
function render(element, container){
  wipRoot = {
    dom: container,
    props: {
      children: [element], // At this time, the element is just a virtual dom tree created by the function.    },
  }
  nextUnitOfWork = wipRoot
}
function commitRoot(){
  commitWork()
  wipRoot = null
}
function commitWork(fiber){
  if(!fiber){
    return
  }
  const domParent = ;
  ()
  commitWork()
  commitWork()
}
function workLoop(deadline) {
  let shouldYield = false
  while (nextUnitOfWork &amp;&amp; !shouldYield) {
    nextUnitOfWork = performUnitOfWork(nextUnitOfWork)
    shouldYield = () &lt; 1
  }
  if(!nextUnitOfWork &amp;&amp; wipRoot){
    commitRoot()
  }
  requestIdleCallback(workLoop)
}
requestIdleCallback(workLoop)
function performUnitOfWork(fiber) {
  // The first step is to create a real dom node based on the fiber node and save it in the properties  if(!){
     = createDom(fiber)
  }
  // Step 2 Add the real dom of the current fiber node to the parent node. Note that this step will trigger the browser to reflow and repaint!  !  !  // if(){
  //   ()
  // }
  // Step 3 Create the corresponding fiber node for the child element  const children = 
  let prevSibling
  ((child, index) =&gt; {
    const newFiber = {
      type: ,
      props: ,
      parent: fiber,
      dom: null
    }
    if(index === 0){
       = newFiber
    } else {
       = newFiber
    }
    prevSibling = newFiber
  })
  // Step 4: Find the next unit of work  if(){
    return 
  }
  let nextFiber = fiber
  while(nextFiber){
    if(){
      return 
    }
    nextFiber = 
  }
}
const MiniReact = {
  createElement:  (type, props, ...children) =&gt; {
    return {
      type,
      props: {
        ...props,
        children: (child =&gt; {
          if(typeof child === 'object'){
            return child
          }
          return {
            type: 'TEXT_ELEMENT',
            props: {
              nodeValue: child,
              children: [],
            }
          }
        })
      }
    }
  },
  render
}
/** @jsx  */
const element = (
  &lt;div&gt;
    &lt;h1&gt;
      &lt;p /&gt;
      &lt;a /&gt;
    &lt;/h1&gt;
    &lt;h2 /&gt;
  &lt;/div&gt;
)
// const element = (
//   &lt;div &gt;
//     &lt;a&gt;bar&lt;/a&gt;
//     &lt;b /&gt;
//   &lt;/div&gt;
// )
('element======', element)
const container = ("root")
(element, container)

Chapter 7 Reconciliation

So far, we have only considered the single scenario of adding dom nodes to containers, and update and deletion have not been implemented yet.

We need to compare the latest onesReact Element TreeAnd the latest oneFiber TreeThe difference

We need to add an alternate attribute to each fiber node to save the old fiber node

The old fiber node saved by alternate has the following main uses:

  • Reuse real dom nodes on old fiber nodes
  • Comparison of props on old fiber nodes and props on new element nodes
  • The old fiber node has updated queues saved, and these queues are executed when creating new fiber nodes to get the latest page
  const children = 
  reconcileChildren(fiber, children)
  function reconcileChildren(wipFiber, elements) {
    let index = 0
    let oldFiber =  && 
    let prevSibling = null
    while (index <  || oldFiber != null) {
      const element = elements[index]
      let newFiber = null
      const sameType = oldFiber && element &&  == 
      if (sameType) {
        newFiber = {
          type: ,
          props: ,
          dom: ,
          parent: wipFiber,
          alternate: oldFiber,
          effectTag: "UPDATE",
        }
      }
      if (element && !sameType) {
        newFiber = {
          type: ,
          props: ,
          dom: null,
          parent: wipFiber,
          alternate: null,
          effectTag: "PLACEMENT",
        }
      }
      if (oldFiber && !sameType) {
         = "DELETION"
        (oldFiber)
      }
      if (oldFiber) {
        oldFiber = 
      }
      if (index === 0) {
         = newFiber
      } else if (element) {
         = newFiber
      }
      prevSibling = newFiber
      index++
    }
}

As shown in the above code:

Coordination process:

  • In essence, it is still creating new ones based on the new React Element TreeFiber Tree, However, in order to save memory overhead, the coordination process will determine whether the new fiber node can reuse the real dom elements on the old fiber node. If it can be reused, there is no need to recreate the real dom elements from beginning to end. At the same time, each new fiber node will also store a reference to the old fiber node, which is convenient for comparing the new and old properties props in the commit stage.
  • ifold andnew The same is true, the old dom node is retained and only the props attribute is updated.
  • iftypeDifferent and havenew element, then create a new real dom node
  • iftypeDifferent and haveold fibernode, delete the real dom node corresponding to the node
  • To delete a node, you need to have a special array to collect the old fiber nodes that need to be deleted. Since the new fiber tree created by the new element tree does not have the corresponding dom, the old fiber nodes need to be collected and deleted during the commit stage

Note that the coordination process is based on the latest React Element Tree to create a new fiber tree, but the new fiber node reuses the real dom elements of the old fiber node. After all, frequent creation of real doms is very memory-consuming. The new fiber node will still save references to the old fiber node, which is convenient for comparing new attributes and old attributes in the commit stage. There will be a question here. If the new fiber node retains references to the old fiber node, then as the number of updates increases, will the old fiber tree also increase and how to destroy it?

import React from 'react';
function createDom(fiber) {
  const dom =  === 'TEXT_ELEMENT' ? ("") : ()
  updateDom(dom, {}, )
  return dom
}
let nextUnitOfWork = null
let wipRoot = null // Save a reference to root fiberlet currentRoot = null // Save the fiber tree corresponding to the current pagelet deletions = null
function render(element, container){
  wipRoot = {
    dom: container,
    props: {
      children: [element], // At this time, the element is just a virtual dom tree created by the function.    },
    alternate: currentRoot,
  }
  deletions = []
  nextUnitOfWork = wipRoot
}
function commitRoot(){
  (commitWork)
  commitWork()
  currentRoot = wipRoot
  wipRoot = null
}
const isEvent = key =&gt; ("on")
const isProperty = key =&gt; key !== "children" &amp;&amp; !isEvent(key)
const isNew = (prev, next) =&gt; key =&gt; prev[key] !== next[key]
const isGone = (prev, next) =&gt; key =&gt; !(key in next)
function updateDom(dom, prevProps, nextProps) {
  //Remove old or changed event listeners
  (prevProps)
    .filter(isEvent)
    .filter(
      key =&gt;
        !(key in nextProps) ||
        isNew(prevProps, nextProps)(key)
    )
    .forEach(name =&gt; {
      const eventType = name
        .toLowerCase()
        .substring(2)
      (
        eventType,
        prevProps[name]
      )
    })
  // Remove old properties
  (prevProps)
    .filter(isProperty)
    .filter(isGone(prevProps, nextProps))
    .forEach(name =&gt; {
      dom[name] = ""
    })
  // Set new or changed properties
  (nextProps)
    .filter(isProperty)
    .filter(isNew(prevProps, nextProps))
    .forEach(name =&gt; {
      dom[name] = nextProps[name]
    })
  // Add event listeners
  (nextProps)
    .filter(isEvent)
    .filter(isNew(prevProps, nextProps))
    .forEach(name =&gt; {
      const eventType = name
        .toLowerCase()
        .substring(2)
      (
        eventType,
        nextProps[name]
      )
    })
}
function commitWork(fiber){
  if(!fiber){
    return
  }
  const domParent = ;
  if ( === "PLACEMENT" &amp;&amp;  != null) {
    ()
  } else if ( === "UPDATE" &amp;&amp;  != null) {
    updateDom(
      ,
      ,
      
    )
  } else if ( === "DELETION") {
    ()
  }
  commitWork()
  commitWork()
}
function workLoop(deadline) {
  let shouldYield = false
  while (nextUnitOfWork &amp;&amp; !shouldYield) {
    nextUnitOfWork = performUnitOfWork(nextUnitOfWork)
    shouldYield = () &lt; 1
  }
  if(!nextUnitOfWork &amp;&amp; wipRoot){
    commitRoot()
  }
  requestIdleCallback(workLoop)
}
requestIdleCallback(workLoop)
function reconcileChildren(wipFiber, elements) {
  let index = 0
  let oldFiber =
       &amp;&amp; 
  let prevSibling = null
  while (index &lt;  || oldFiber != null) {
    const element = elements[index]
    let newFiber = null
    const sameType = oldFiber &amp;&amp; element &amp;&amp;  == 
    if (sameType) {
      newFiber = {
        type: ,
        props: ,
        dom: ,
        parent: wipFiber,
        alternate: oldFiber,
        effectTag: "UPDATE",
      }
    }
    if (element &amp;&amp; !sameType) {
      newFiber = {
        type: ,
        props: ,
        dom: null,
        parent: wipFiber,
        alternate: null,
        effectTag: "PLACEMENT",
      }
    }
    if (oldFiber &amp;&amp; !sameType) {
       = "DELETION"
      (oldFiber)
    }
    if (oldFiber) {
      oldFiber = 
    }
    if (index === 0) {
       = newFiber
    } else if (element) {
       = newFiber
    }
    prevSibling = newFiber
    index++
  }
}
function performUnitOfWork(fiber) {
  // The first step is to create a real dom node based on the fiber node and save it in the properties  if(!){
     = createDom(fiber)
  }
  // Step 2 Add the real dom of the current fiber node to the parent node. Note that this step will trigger the browser to reflow and repaint!  !  !  // if(){
  //   ()
  // }
  // Step 3 Create the corresponding fiber node for the child element  const children = 
  // let prevSibling
  // ((child, index) =&gt; {
  //   const newFiber = {
  //     type: ,
  //     props: ,
  //     parent: fiber,
  //     dom: null
  //   }
  //   if(index === 0){
  //      = newFiber
  //   } else {
  //      = newFiber
  //   }
  //   prevSibling = newFiber
  // })
  reconcileChildren(fiber, children)
  // Step 4: Find the next unit of work  if(){
    return 
  }
  let nextFiber = fiber
  while(nextFiber){
    if(){
      return 
    }
    nextFiber = 
  }
}
const MiniReact = {
  createElement:  (type, props, ...children) =&gt; {
    return {
      type,
      props: {
        ...props,
        children: (child =&gt; {
          if(typeof child === 'object'){
            return child
          }
          return {
            type: 'TEXT_ELEMENT',
            props: {
              nodeValue: child,
              children: [],
            }
          }
        })
      }
    }
  },
  render
}
/** @jsx  */
const container = ("root")
const updateValue = e =&gt; {
  rerender()
}
const rerender = value =&gt; {
  const element = (
    &lt;div&gt;
      &lt;input onInput={updateValue} value={value} /&gt;
      &lt;h2&gt;Hello {value}&lt;/h2&gt;
    &lt;/div&gt;
  )
  (element, container)
}
rerender("World")

Chapter 8 Function Components

The following code in this chapter is an example:

/** @jsx  */
const container = ("root")
function App(props){
  return <h1>Hi {  }</h1>
}
const element = <App name="foo" />
(element, container)

After jsx is compiled by babel:

function App(props) {
  return ("h1", null, "Hi ", );
}
const element = (App, {
  name: "foo"
});

There are two differences between function components:

  • The fiber node corresponding to the function component does not have a corresponding real dom element.
  • You need to execute a function to get the corresponding children node, rather than directly fromGet

Since the function component does not have a corresponding fiber node, when looking for the dom corresponding to the parent fiber node during the commit stage, it is necessary to determine whether the dom element exists.

The complete code of this chapter:

import React from 'react';
function createDom(fiber) {
  const dom =  === 'TEXT_ELEMENT' ? ("") : ()
  updateDom(dom, {}, )
  return dom
}
let nextUnitOfWork = null
let wipRoot = null // Save a reference to root fiberlet currentRoot = null // Save the fiber tree corresponding to the current pagelet deletions = null
function render(element, container){
  wipRoot = {
    dom: container,
    props: {
      children: [element], // At this time, the element is just a virtual dom tree created by the function.    },
    alternate: currentRoot,
  }
  deletions = []
  nextUnitOfWork = wipRoot
}
function commitRoot(){
  (commitWork)
  commitWork()
  currentRoot = wipRoot
  wipRoot = null
}
const isEvent = key =&gt; ("on")
const isProperty = key =&gt; key !== "children" &amp;&amp; !isEvent(key)
const isNew = (prev, next) =&gt; key =&gt; prev[key] !== next[key]
const isGone = (prev, next) =&gt; key =&gt; !(key in next)
function updateDom(dom, prevProps, nextProps) {
  //Remove old or changed event listeners
  (prevProps)
    .filter(isEvent)
    .filter(
      key =&gt;
        !(key in nextProps) ||
        isNew(prevProps, nextProps)(key)
    )
    .forEach(name =&gt; {
      const eventType = name
        .toLowerCase()
        .substring(2)
      (
        eventType,
        prevProps[name]
      )
    })
  // Remove old properties
  (prevProps)
    .filter(isProperty)
    .filter(isGone(prevProps, nextProps))
    .forEach(name =&gt; {
      dom[name] = ""
    })
  // Set new or changed properties
  (nextProps)
    .filter(isProperty)
    .filter(isNew(prevProps, nextProps))
    .forEach(name =&gt; {
      dom[name] = nextProps[name]
    })
  // Add event listeners
  (nextProps)
    .filter(isEvent)
    .filter(isNew(prevProps, nextProps))
    .forEach(name =&gt; {
      const eventType = name
        .toLowerCase()
        .substring(2)
      (
        eventType,
        nextProps[name]
      )
    })
}
function commitWork(fiber){
  if(!fiber){
    return
  }
  let domParentFiber = 
  while(!){
    domParentFiber = 
  }
  const domParent = ;
  if ( === "PLACEMENT" &amp;&amp;  != null) {
    ()
  } else if ( === "UPDATE" &amp;&amp;  != null) {
    updateDom(, , )
  } else if ( === "DELETION") {
    // ()
    commitDeletion(fiber, domParent)
  }
  commitWork()
  commitWork()
}
function commitDeletion(fiber, domParent){
  if(){
    ()
  } else {
    commitDeletion(, domParent)
  }
}
function workLoop(deadline) {
  let shouldYield = false
  while (nextUnitOfWork &amp;&amp; !shouldYield) {
    nextUnitOfWork = performUnitOfWork(nextUnitOfWork)
    shouldYield = () &lt; 1
  }
  if(!nextUnitOfWork &amp;&amp; wipRoot){
    commitRoot()
  }
  requestIdleCallback(workLoop)
}
requestIdleCallback(workLoop)
function reconcileChildren(wipFiber, elements) {
  let index = 0
  let oldFiber =
       &amp;&amp; 
  let prevSibling = null
  while (index &lt;  || oldFiber != null) {
    const element = elements[index]
    let newFiber = null
    const sameType = oldFiber &amp;&amp; element &amp;&amp;  == 
    if (sameType) {
      newFiber = {
        type: ,
        props: ,
        dom: ,
        parent: wipFiber,
        alternate: oldFiber,
        effectTag: "UPDATE",
      }
    }
    if (element &amp;&amp; !sameType) {
      newFiber = {
        type: ,
        props: ,
        dom: null,
        parent: wipFiber,
        alternate: null,
        effectTag: "PLACEMENT",
      }
    }
    if (oldFiber &amp;&amp; !sameType) {
       = "DELETION"
      (oldFiber)
    }
    if (oldFiber) {
      oldFiber = 
    }
    if (index === 0) {
       = newFiber
    } else if (element) {
       = newFiber
    }
    prevSibling = newFiber
    index++
  }
}
function performUnitOfWork(fiber) {
  // 1. The fiber node corresponding to the function component does not have real dom elements  // 2. Function components need to run functions to get children  const isFunctionComponent =  instanceof Function
  if(!isFunctionComponent &amp;&amp; !){
     = createDom(fiber)
  }
  const children = isFunctionComponent ? [()] : 
  // Step 2 Create a corresponding fiber node for each new react element node and determine whether the real dom element on the old fiber node can be reused.  // Save the overhead of creating real dom elements  reconcileChildren(fiber, children)
  // Step 3: Find the next unit of work  if(){
    return 
  }
  let nextFiber = fiber
  while(nextFiber){
    if(){
      return 
    }
    nextFiber = 
  }
}
const MiniReact = {
  createElement:  (type, props, ...children) =&gt; {
    return {
      type,
      props: {
        ...props,
        children: (child =&gt; {
          if(typeof child === 'object'){
            return child
          }
          return {
            type: 'TEXT_ELEMENT',
            props: {
              nodeValue: child,
              children: [],
            }
          }
        })
      }
    }
  },
  render
}
/** @jsx  */
const container = ("root")
function App(props){
  return &lt;h1&gt;Hi {  }&lt;/h1&gt;
}
const element = &lt;App name="foo" /&gt;
(element, container)

Chapter 9 Hooks

The complete code of this chapter

import React from 'react';
function createDom(fiber) {
  const dom =  === 'TEXT_ELEMENT' ? ("") : ()
  updateDom(dom, {}, )
  return dom
}
let nextUnitOfWork = null
let wipRoot = null // Save a reference to root fiberlet currentRoot = null // Save the fiber tree corresponding to the current pagelet deletions = null
function render(element, container){
  wipRoot = {
    dom: container,
    props: {
      children: [element], // At this time, the element is just a virtual dom tree created by the function.    },
    alternate: currentRoot,
  }
  deletions = []
  nextUnitOfWork = wipRoot
}
function commitRoot(){
  (commitWork)
  commitWork()
  currentRoot = wipRoot
  wipRoot = null
}
const isEvent = key =&gt; ("on")
const isProperty = key =&gt; key !== "children" &amp;&amp; !isEvent(key)
const isNew = (prev, next) =&gt; key =&gt; prev[key] !== next[key]
const isGone = (prev, next) =&gt; key =&gt; !(key in next)
function updateDom(dom, prevProps, nextProps) {
  //Remove old or changed event listeners
  (prevProps)
    .filter(isEvent)
    .filter(
      key =&gt;
        !(key in nextProps) ||
        isNew(prevProps, nextProps)(key)
    )
    .forEach(name =&gt; {
      const eventType = name
        .toLowerCase()
        .substring(2)
      (
        eventType,
        prevProps[name]
      )
    })
  // Remove old properties
  (prevProps)
    .filter(isProperty)
    .filter(isGone(prevProps, nextProps))
    .forEach(name =&gt; {
      dom[name] = ""
    })
  // Set new or changed properties
  (nextProps)
    .filter(isProperty)
    .filter(isNew(prevProps, nextProps))
    .forEach(name =&gt; {
      dom[name] = nextProps[name]
    })
  // Add event listeners
  (nextProps)
    .filter(isEvent)
    .filter(isNew(prevProps, nextProps))
    .forEach(name =&gt; {
      const eventType = name
        .toLowerCase()
        .substring(2)
      (
        eventType,
        nextProps[name]
      )
    })
}
function commitWork(fiber){
  if(!fiber){
    return
  }
  let domParentFiber = 
  while(!){
    domParentFiber = 
  }
  const domParent = ;
  if ( === "PLACEMENT" &amp;&amp;  != null) {
    ()
  } else if ( === "UPDATE" &amp;&amp;  != null) {
    updateDom(, , )
  } else if ( === "DELETION") {
    // ()
    commitDeletion(fiber, domParent)
  }
  commitWork()
  commitWork()
}
function commitDeletion(fiber, domParent){
  if(){
    ()
  } else {
    commitDeletion(, domParent)
  }
}
function workLoop(deadline) {
  let shouldYield = false
  while (nextUnitOfWork &amp;&amp; !shouldYield) {
    nextUnitOfWork = performUnitOfWork(nextUnitOfWork)
    shouldYield = () &lt; 1
  }
  if(!nextUnitOfWork &amp;&amp; wipRoot){
    commitRoot()
  }
  requestIdleCallback(workLoop)
}
requestIdleCallback(workLoop)
function reconcileChildren(wipFiber, elements) {
  let index = 0
  let oldFiber =
       &amp;&amp; 
  let prevSibling = null
  while (index &lt;  || oldFiber != null) {
    const element = elements[index]
    let newFiber = null
    const sameType = oldFiber &amp;&amp; element &amp;&amp;  == 
    if (sameType) {
      newFiber = {
        type: ,
        props: ,
        dom: ,
        parent: wipFiber,
        alternate: oldFiber,
        effectTag: "UPDATE",
      }
    }
    if (element &amp;&amp; !sameType) {
      newFiber = {
        type: ,
        props: ,
        dom: null,
        parent: wipFiber,
        alternate: null,
        effectTag: "PLACEMENT",
      }
    }
    if (oldFiber &amp;&amp; !sameType) {
       = "DELETION"
      (oldFiber)
    }
    if (oldFiber) {
      oldFiber = 
    }
    if (index === 0) {
       = newFiber
    } else if (element) {
       = newFiber
    }
    prevSibling = newFiber
    index++
  }
}
function performUnitOfWork(fiber) {
  // 1. The fiber node corresponding to the function component does not have real dom elements  // 2. Function components need to run functions to get children  const isFunctionComponent =  instanceof Function
  if(!isFunctionComponent &amp;&amp; !){
     = createDom(fiber)
  }
  const children = isFunctionComponent ? updateFunctionComponent(fiber) : 
  // Step 2 Create a corresponding fiber node for each new react element node and determine whether the real dom element on the old fiber node can be reused.  // Save the overhead of creating real dom elements  reconcileChildren(fiber, children)
  // Step 3: Find the next unit of work  if(){
    return 
  }
  let nextFiber = fiber
  while(nextFiber){
    if(){
      return 
    }
    nextFiber = 
  }
}
let wipFiber = null
let hookIndex = null
function updateFunctionComponent(fiber){
  wipFiber = fiber
  hookIndex = 0
   = []
  return [()]
}
function useState(initial){
  const oldHook =  &amp;&amp;  &amp;&amp; [hookIndex]
  const hook = {
    state: oldHook ?  : initial,
    queue: [],
  }
  const actions = oldHook ?  : []
  (action =&gt; {
     = action()
  })
  const setState = action =&gt; {
    (action)
    wipRoot = {
      dom: ,
      props: ,
      alternate: currentRoot,
    }
    nextUnitOfWork = wipRoot
    deletions = []
  }
  (hook)
  hookIndex++
  return [, setState]
}
const MiniReact = {
  createElement:  (type, props, ...children) =&gt; {
    return {
      type,
      props: {
        ...props,
        children: (child =&gt; {
          if(typeof child === 'object'){
            return child
          }
          return {
            type: 'TEXT_ELEMENT',
            props: {
              nodeValue: child,
              children: [],
            }
          }
        })
      }
    }
  },
  render,
  useState,
}
/** @jsx  */
const container = ("root")
function Counter(){
  const [state, setState] = (1)
  return (
    &lt;h1 onClick={() =&gt; setState(c =&gt; c + 1)}&gt;
      Count: { state }
    &lt;/h1&gt;
  )
}
const element = &lt;Counter /&gt;
(element, container)

This is the article about the comprehensive and in-depth analysis of the core principles of the React framework. For more related core content of the React framework, please search for my previous articles or continue browsing the related articles below. I hope everyone will support me in the future!