|
| 1 | +--- |
| 2 | +slug: intro-to-react-fiber |
| 3 | +title: Introduction to React Fiber |
| 4 | +description: A comprehensive guide to understanding React Fiber, its architecture, and how it improves React performance |
| 5 | +keywords: [react, react fiber, javascript, web development, performance] |
| 6 | +image: ./diff.jpg |
| 7 | +authors: [gazcn007] |
| 8 | +tags: [react, javascript, web development] |
| 9 | +--- |
| 10 | + |
| 11 | +import { ReactFiber, SlideShow } from '@patternize/components'; |
| 12 | + |
| 13 | +:::info |
| 14 | +This blog will explain React Fiber Internal Algorithms, we will: |
| 15 | + |
| 16 | +- Revisit how React diff works |
| 17 | +- Problems with Tree Traversal |
| 18 | +- Morris Traversal |
| 19 | + |
| 20 | +It's recommended to have a basic understanding of React, virtualDOM, and diff before reading this blog. |
| 21 | +::: |
| 22 | + |
| 23 | +You can first experience the difference between React Fiber (v17+) and pre-Fiber (v16) by playing with the playground below: |
| 24 | + |
| 25 | +<ReactFiber /> |
| 26 | + |
| 27 | +You can tell a huge difference between the two versions, the old reconcilor is very slow, but the fiber one is very smooth. |
| 28 | + |
| 29 | + |
| 30 | + |
| 31 | +### Diff Calculation of React |
| 32 | + |
| 33 | +React's diff calculation is based on the virtualDOM, which is a tree structure that represents the UI. When a state change happens, React will calculate the difference between the old virtualDOM and the new virtualDOM, and then apply the changes to the realDOM. |
| 34 | + |
| 35 | + |
| 36 | + |
| 37 | +However, calculating the edit distance of two unordered trees is NP-Complete, and the standard algorithm needs at least a runtime of **O(n^3)**. |
| 38 | + |
| 39 | +:::tip |
| 40 | + |
| 41 | +There are papers that show that the problem is NP-Complete. Because it is equivalent to a graph isomorphism problem. |
| 42 | + |
| 43 | + |
| 44 | + |
| 45 | +::: |
| 46 | + |
| 47 | +React uses a **heuristic approach** that compares nodes level-by-level rather than doing an exhaustive node-by-node comparison. While this may sometimes update more nodes than strictly necessary, it ensures no required updates are missed while being much more efficient than a full tree traversal. The algorithm trades perfect accuracy for speed and predictability. |
| 48 | + |
| 49 | + |
| 50 | + |
| 51 | +You can see the heuristic approach of diff traversal in the gif below - **React compares the tree level by level instead of node by node.** |
| 52 | + |
| 53 | + |
| 54 | + |
| 55 | +### Problem with Recursion |
| 56 | + |
| 57 | +What’s wrong with doing a full tree traversal for diff in the above animation? |
| 58 | + |
| 59 | +Well, there are two problems with traversing the tree using recursion, we all know in computer science: |
| 60 | + |
| 61 | +1. For any tree recursion, the call stack is O(n) |
| 62 | +2. It is impossible to pause the traversal and stop the stack from growing while you are doing recursion. |
| 63 | + |
| 64 | +**Here is an interactive slide show of the call stack of the recursion stack:** |
| 65 | + |
| 66 | +(You can navigate back and forth using Previous and Next button) |
| 67 | + |
| 68 | +export const StackSlideShow = () => { |
| 69 | +const images = [ |
| 70 | +'/slideshow/React-Stack/React-Fiber.001.jpeg', |
| 71 | +'/slideshow/React-Stack/React-Fiber.002.jpeg', |
| 72 | +'/slideshow/React-Stack/React-Fiber.003.jpeg', |
| 73 | +'/slideshow/React-Stack/React-Fiber.004.jpeg', |
| 74 | +'/slideshow/React-Stack/React-Fiber.005.jpeg', |
| 75 | +'/slideshow/React-Stack/React-Fiber.006.jpeg', |
| 76 | +'/slideshow/React-Stack/React-Fiber.007.jpeg' |
| 77 | +]; |
| 78 | +return <SlideShow maxWidth='1000px' maxHeight='460px' images={images}/>; |
| 79 | +} |
| 80 | + |
| 81 | +<StackSlideShow /> |
| 82 | + |
| 83 | +## Solution to the problems - Morris Traversal |
| 84 | + |
| 85 | +Morris Traversal is a way to traverse a tree without using recursion. It is a linear time algorithm that uses a single stack to store the nodes. |
| 86 | + |
| 87 | +**Here is an interactive slide show of traversing the tree with Morris Traversal:** |
| 88 | + |
| 89 | +export const FiberSlideShow = () => { |
| 90 | +const images = [ |
| 91 | +'/slideshow/React-Fiber/React-Fiber.001.jpeg', |
| 92 | +'/slideshow/React-Fiber/React-Fiber.002.jpeg', |
| 93 | +'/slideshow/React-Fiber/React-Fiber.003.jpeg', |
| 94 | +'/slideshow/React-Fiber/React-Fiber.004.jpeg', |
| 95 | +'/slideshow/React-Fiber/React-Fiber.005.jpeg', |
| 96 | +'/slideshow/React-Fiber/React-Fiber.006.jpeg', |
| 97 | +'/slideshow/React-Fiber/React-Fiber.007.jpeg', |
| 98 | +'/slideshow/React-Fiber/React-Fiber.008.jpeg', |
| 99 | +'/slideshow/React-Fiber/React-Fiber.009.jpeg', |
| 100 | +'/slideshow/React-Fiber/React-Fiber.010.jpeg', |
| 101 | +'/slideshow/React-Fiber/React-Fiber.011.jpeg' |
| 102 | +]; |
| 103 | +return <SlideShow maxWidth='1000px' maxHeight='460px' images={images}/>; |
| 104 | +} |
| 105 | + |
| 106 | +<FiberSlideShow /> |
| 107 | + |
| 108 | +**With Morris Traversal, the call stack is constant O(1) space. Runtime is O(1) for each evaluation. And you can pause the traversal anytime!** |
| 109 | + |
| 110 | +This is exactly what React Fiber is doing in their code - adding more path between the nodes to turn a tree into a graph like Morris Traversal. |
| 111 | + |
| 112 | + |
| 113 | + |
| 114 | +## React Fiber with concurrency |
| 115 | + |
| 116 | +What you can do with fiber once you have O(1) time and space for each evaluation and being able to pause the traversal is concurrent rendering. |
| 117 | + |
| 118 | +This is how React Fiber achieves concurrent rendering, you can see the animation below: |
| 119 | + |
| 120 | +export const ConcurrencySlideShow = () => { |
| 121 | +const images = [ |
| 122 | +'/slideshow/React-Fiber-Concurrency/React-Fiber-Concurrency.001.jpeg', |
| 123 | +'/slideshow/React-Fiber-Concurrency/React-Fiber-Concurrency.002.jpeg', |
| 124 | +'/slideshow/React-Fiber-Concurrency/React-Fiber-Concurrency.003.jpeg', |
| 125 | +'/slideshow/React-Fiber-Concurrency/React-Fiber-Concurrency.004.jpeg', |
| 126 | +'/slideshow/React-Fiber-Concurrency/React-Fiber-Concurrency.005.jpeg', |
| 127 | +'/slideshow/React-Fiber-Concurrency/React-Fiber-Concurrency.006.jpeg', |
| 128 | +'/slideshow/React-Fiber-Concurrency/React-Fiber-Concurrency.007.jpeg' |
| 129 | +]; |
| 130 | +return <SlideShow maxWidth='1000px' maxHeight='460px' images={images}/>; |
| 131 | +} |
| 132 | + |
| 133 | +<ConcurrencySlideShow /> |
0 commit comments