Skip to content

CrazyFork/react-fiber-implement

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

12 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Notes

咋说呢这里的实现只能是大部分, 细节其实很粗糙, 有的地方还有bug, 但是不影响对fiber的理解. 尤其是data structure的应用

folder structure

src
├── core
│   ├── h.js                              // jsx function, create virtual node
│   ├── life-cycle.js                     // unmount/mount
│   └── with-state.js                     // like useState in react
├── dom                                   // this is like react-dom, manipulate dom, expose `render` function
│   ├── config.js
│   ├── constants.js
│   ├── index.js
│   └── utils                             // dom operaions
│       ├── append.js
│       ├── createElement.js
│       ├── getDocumentByElement.js
│       ├── insert.js
│       ├── remove.js
│       ├── textElement.js
│       └── validate.js
├── fiber                                 // filber implementation
│   ├── begin-work.js                     // start to process fiber node
│   ├── children.js                       // ! reconciler children
│   ├── commit-work.js                    // commit phase
│   ├── complete-work.js                  // will call this after each fiber got processed
│   ├── f-life-cycle.js                   
│   ├── f-node.js                         // fiber node
│   ├── f-with.js                         // state node, useState will created a state node in fiber
│   ├── host-context.js                   // statck to preserve a global host variable
│   ├── reconciler.js                     // ! this is the most important one, pls see react official doc about reconciliation
│   ├── root-render.js                    
│   ├── scheduler.js                      // requestIdleCallback
│   └── stack.js
├── shared
│   ├── effect-tag.js                     // update/insertion/deletion tag
│   ├── shallowEqual.js
│   ├── status-work.js
│   ├── tag.js                            // tag of each kind of fiber node
│   ├── types.js
│   ├── validate.js
│   └── with-effect.js                    // 
└── structures
    └── linked-list.js

common types

// type: List<Tuple<Key, Value>>
updatePayload 


// state node, created by calling useState
// the basic structure is this 
//
// a [fiber node]
//    |
//    [ state node #1]          <- [a, dispatchA] = useState(1)
//    |   |
//    |   [queue node #1]         <- dispatchA(2)
//    |   |
//    |   [queue node #2]         <- dispatchA(3)
//    [ state node #1]         <- [b, dispatchB] useState(1)
//        |
//        [queue node #1]         <- dispatchB(a)
//        |
//        [queue node #2]        <- dispatchB(b)



common code

// double assignment
a = b = c
// is
b = c;
a = b;


//
WIP // refer to current working fiber node
current: FNode // refer to active fiber node

vnode // react virtual node
fnode // react fiber node
// in children.js
  function placeChild(newFNode, lastPlacedIndex, newIndex) {
    newFNode.index = newIndex;
    const current = newFNode.alternate;
    if (current !== null) {
      const oldIndex = current.index;
      if (oldIndex < lastPlacedIndex) {
        // this is a move
        newFNode.effectTag = Placement;
        return lastPlacedIndex;
      } else {
        // this item can stay in place
        return oldIndex;
      }
    } else {
      // this is an insertion.
      newFNode.effectTag = Placement;
      return lastPlacedIndex;
    }
  }

classic DFS search in Fiber



function appendAllChildren(
  parent,
  WIP
) {
  let node = WIP.child;
    // traverse all nodes
  while (node !== null) {
    if (node.tag === DNode || node.tag === Text) {
        // update dom
      appendInitialChild(parent, node.instanceNode);
        // ^ it should back from here
        // node = node.return
    } else if (node.child !== null) {
        // ^ why else if
        // dive down
      node.child.return = node;
      node = node.child;
      continue;
    }
      // back to beginning
    if (node === WIP) {
      return;
    }
      // try sibling
    while (node.sibling === null) {
      if (node.return === null || node.return === WIP) {
        return;
      }
      node = node.return;
    }
    node.sibling.return = node.return;
    node = node.sibling;
  }
}


React fiber

react-fiber is my self-study project help me understand how react work. In fact, all �codebase re-implement each step , so it looks similar to the source code of react. Though, I think it's still smaller and easier to understand than when you actually read the react source code. I hope it helpful for people who want to start learn how react fiber work.

Something you should read and learn before start read source code

Keyword, Algorithms and Data Structure Used

  • Single linked list, Circular linked list
  • Simple stack and queue
  • Recursive
  • Structural sharing
  • Reconciliation
  • Scheduler
  • Bitwise Operators
  • JSX
  • DOM
And more
Recommend

Overview

Fiber tree

Inside Fiber: in-depth overview of the new reconciliation algorithm in React

Keyword

work (unitOfWork): A component, node element => fiber

current: Current fiber what is displayed on browser

WIP (workInProgress): New fiber tree we will build

fiber: {
  type: string | Function ('div', 'span', function Button)
  instanceNode: HTMLElement (div, span)
  return: fiber (parent of fiber)
  child: fiber (child of fiber)
  sibling: fiber (sibling of fiber)

  alternate: link current - WIP and WIP - current
  effectTag: number (give we know what will happen this fiber)

}

requestIdleCallback

main function:
  createWorkInProgress()
  beginWork()
  reconcileChildren()
  completeWork()
  commitWork()

Process of first render

Render -> Reconciler -> Scheduler ->
Begin Work (build fiber tree) -> ChildReconciler(create child and effectTag) -> if work has child we will continue to run beginWork -> no child ->              
Complete Work (build list effect, mark tag and create instanceNode) -> sibling has child -> turn back Begin Work -> no child -> Complete Work -> no sibling -> has a new tree with effect tag ->
Commit Work : It will base on list effect tag to commit each fiber (Placement, Update, Delete, Lifecycle)

// In first render current fiber is null.
// current is workInProgress when commit

Process when update

Do something ->
Get current Fiber what corresponding to the component ->
Recursive to find Root ->
Clone fiber from root to component has update ->
Begin Work from this fiber (it's maybe clone fiber when children of component use memo, pure component or use shouldComponentUpdate) ->
Complete Work ->
Commit Work

About With(Hook v16.7)

Hooks are stored as a linked list on the fiber's prevState field of fiber.
current tree - current hook <=> WIP - WIP hook

About

re-implement react fiber

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Languages

  • JavaScript 99.8%
  • HTML 0.2%