Loading [MathJax]/jax/output/CommonHTML/config.js
前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >专栏 >新的一年,从手写mini react开始

新的一年,从手写mini react开始

作者头像
FE情报局
发布于 2023-01-31 03:22:39
发布于 2023-01-31 03:22:39
50100
代码可运行
举报
文章被收录于专栏:FE情报局FE情报局
运行总次数:0
代码可运行

大家好,这里是【FE情报局】

作为前端来说,工作三年以上,如果你还是不会或者不了解如何手写一些最基础的框架,对于当前的形势来说是不太友好的,了解框架原理,手写框架已经成为前端开发者最基础的知识技能了,学习框架设计思维,结合业务体系,能够更好的做开发和优化

react作为前端热门框架之一,学习了解手写其中的原理也是前端们需要掌握的技能之一,了解如何一步一步实现一个简易的react,能够更深刻的了解react原理,hook的原理和机制,使用起来才能够更加得心应手

我会参照build-your-own-react这个项目,一步一步实现一个mini react

当然这不会涉及到react中一些非必要的功能,比如一些优化,但是会遵循react的设计理念

前沿

首先我们可以了解一些react的基本概念和内容,使用一个react很简单,只需要三行代码,我们详细来讲述一下这三行代码

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const element = <span class='text'>FE情报局</span>
const root = document.getElementById('root')
ReactDOM.render(element, root)

ele定义了一个dom节点,root是html中body下面的根元素,然后使用 ReactDOM.render将ele的dom插入到root节点下,熟悉react的同学对这个内容都不陌生,这是react项目入口写法

将其替换成原始的javascript代码应该怎么实现呢?

首先第一行,这是一段jsx代码,在原生的javascript中是不会被识别的,将其变成原生React代码应该是这样的

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// const element = <span class='text'>FE情报局</span>
const element = React.createElement(
  'span',
  {
    class: 'text'
  },
  'FE情报局'
)

对于jsx代码的转换通常是通过babel工具,将jsx的代码转换成js认识的代码

createElement第一个参数是元素类型,第二个是元素属性,其中有一个特殊的节点children,之后会讲到,之后所有的参数都是子节点内容,可以是一个字符串,也可以是另一个节点

转换过程通常也比较简单,了解babel的人对AST过程比较熟悉,将jsx代码通过parse生成AST语法树,然后通过transform再将其进行转换,变成最终的AST语法树,最后再generate将AST语法树转换成最终的结果,transform阶段其实就是将jsx代码转换成对createElement的调用,将标签,属性,以及子元素当参数进行传递

但是createElement并不会直接创建一个dom元素,而是创建一个object,这个object就是我们常说的虚拟dom,本质就是一个js对象,这个对象包含以下内容,当然最主要的内容是这几个,更多的虚拟dom属性可以自己了解

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const element = {
  type: 'span',
  props: {
    class: 'text',
    children: 'FE情报局'
  }
}

这个虚拟dom就可以完全表示一个真实dom,其中type是DOM节点类型,当然也可以是一个函数,后续会做说明

props是一个对象,具有jsx属性中所有的健值对,还有一个特殊的属性children,当前这个情况children是一个字符串,它也可以是嵌套的其它内容,比如可以再嵌套一个数组,数组内容可以是element或者字符串,这也就说明为什么虚拟dom是个树形结构

最后一行代码ReactDOM.render,就是用来生成真实dom,目的是为了将element插入到root节点当中,用原生js替换一下

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// ReactDOM.render(element, root)
const node = document.createElement(element.type)
node['class'] = ele.props.class

const text = document.createTextNode('')
text['nodeValue'] = ele.props.children

首先我们创建了一个span的节点,然后将class赋值给节点,node表示真实dom节点,然后创建子节点元素,子元素就是一段text,所以创建一个text节点,这里不用innerText主要是这种方式不可以处理多种格式的children,使用createNode的形式可以直接处理props,比如这里我们可以将porps改成props: {nodeValue: "FE情报局"}

最后,我们将textNode插入到span标签中,将node插入到root元素下

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
node.appendChild(text)
root.appendChild(node)

最终,我们将react代码转换成了js原生代码,有了这些认知,我们将开始正经写一个mini react内容

createElement函数

在前沿里面,我们使用了React官方提供的一些方法,虽然使用原生js也实现了一些基本的功能,但是只是按逻辑实现,并没有做一些较好的封装,所以我们要自己写一个mini React,提供一些通用方法,达到原生React功能的目的

首先先编写createElement函数,来一个稍微复杂一点的例子

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const ele = (
  <div class='box'>
    <a>FE情报局</a>
    <br />
  </div>
)
const root = document.getElementById('root')
ReactDOM.render(ele, root)

还记得React.createElement的调用方式么?通过一些传参,它返回一个虚拟dom,也就是一个js对象

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function createElement(type, props, ...children){
  return {
    type,
    props: {
      ...props,
      children
    }
  }
}

const element = createElement(
  'div',
  {
    class: 'box',
  },
  createElement('a', null, 'FE情报局'),
  createElement('br')
)

这里讲一个小技巧,我们使用的扩展运算符,会导致如果你不传子元素,默认children是一个数组,比如我们调用createElement('div')

传了后续的内容,自然也是一个数组,保证了格式的统一

当然children的数据类型较多,比如它可以是数字,字符串,也可以是一个虚拟dom,如果不是一个对象,则它就是自己的一个内容,那我们可以为其创造一个类型标识:TEXT_ELEMENT

完善一下createElement的逻辑,判断传入的children类型

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function createElement(type, props, ...children){
  return {
    type,
    props: {
      ...props,
      children: children.map(child => {
        if(typeof child === 'object'){
          return child
        }
        return createTextElement(child)
      })
    }
  }
}

// 编写createTextElement,同样返回虚拟dom,也就是一个js对象
function createTextElement(text) 
{
  return {
    type: 'TEXT_ELEMENT',
    props: {
      nodeValue: text,
      children: []
    }
  }
}

然后我们取名MiniReact,可以通过MiniReact.createElement方式进行调用

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
const MiniReact = {
  createElement
}

render方法

现在我们要实现render方法,将虚拟dom转成真实dom,并挂在到对应的节点,第一个参数是ele虚拟dom,第二个是要挂在的dom元素,当前我们先完成在挂在的dom元素后追加

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function render(ele, container){
  // 先判断ele.type是否为text然后执行对应的逻辑
  const dom = ele.type === 'TEXT_ELEMENT' ? document.createTextNode('') : document.createElement(ele.type)
  // props中属性追加到dom元素中,但是要注意去除children属性,所以要先做一层过滤
  const isProperty = key => key !== 'children'
  Object.keys(ele.props).filter(isProperty).forEach(name => {
    dom[name] = ele.props[name]
  })
  
  // 将children遍历调用render
  ele.props.children.forEach(child =>
    render(child, dom)
  )
  
  container.appendChild(dom)
}

最后将render方法挂在到MiniReact

并发模式

在进行功能追加的时候,我们需要重构一下之前的内容

那我们之前的内容有什么问题呢?细心的同学就会发现,如果我们在人render的时候传入的虚拟dom树过于庞大,而render方法中总是不断的去递归虚拟dom中的children,那就会存在在执行render的时候,整个js线程被阻塞,并且停不下来,导致用户输入或者页面渲染卡顿,必须等render函数执行完成才有响应

所以这个就涉及到react中的时间切片的概念了,我们需要将大量的执行任务分割成小的单元,这个小的单元会在屏幕更新的间隙完成,每次完成之后看是否有其它事情做,如果有则中断render,执行完成之后,再将render继续执行

那如何知道浏览器是否空闲呢?window.requestIdleCallback就可以知道,这个方法插入一个函数,这个函数就会在浏览器空闲的时间去调用

当然react肯定不是使用window.requestIdleCallback,它们有自己的调度器,由于我们是MiniReact,所以我们使用window.requestIdleCallback就可以了,本质是一样的

我们先简单实现一下,然后再来具体介绍一下

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
let nextUnitOfWork = null

function workLoop(deadline) {
  let shouldYield = false
  while(nextUnitOfWork && !shouldYield){
    nextUnitOfWork = performUnitOfWork(nextUnitOfWork)
    shouldYield = deadLine.timeRemaining() < 1
  }
  requestIdleCallback(workLoop)
}

requestIdleCallback(workLoop)

requestIdleCallback这个函数接收到要执行的函数之后,会给这个函数传递一个参数,这个参数可以获取当前空闲时间以及回调是否在超时时间前已经执行的状态

比如上述的deadline,就是回调函数的参数,deadLine.timeRemaining()表示浏览器需要执行其它逻辑的时候我们还有多少时间

这里表示如果这个时间小于1,那么这个while循环就被停止,执行被暂停,将控制权交给浏览器

然后当浏览器空闲的时候,继续执行workLoop,查看是否有nextUnitOfWork,也就是要开始执行逻辑,同时我们必须要有一个performUnitOfWork函数,用来执行nextUnitOfWork并且要返回下一个nextUnitOfWork

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function performUnitOfWork(nextUnitOfWork){
  // TODO
}

Fibers

为了实现我们上述的performUnitOfWork这个函数,我们需要组织一下我们对应的工作单元,也就是需要支持我们的虚拟dom能够渐进式渲染,对整个大的虚拟dom或者任务进行分片,分片完成之后要能够支持分片任务的挂起、恢复、终止等操作,并且任务都有优先级,这个时候就要提到我们的Fiber

在这个架构中,引入了一个新的数据结构,Fiber节点,这个节点根据虚拟dom生成,然后通过Fiber节点生成真实dom

为了尽可能细化我们每个单元的操作,需要每个元素都应该有一个fiber,每一个fiber都是一个工作单元,确保执行的速度,举个例子,假设我们有这样一个dom结构,将其挂在到root节点

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
<div>
  <h1>
    <p />
    <a />
  </h1>
  <h2 />
</div>

拿到这个内容,babel会将其转换成虚拟dom,然后通过虚拟dom数据,转换成fiber的数据结构

我们首先需要创建一个root fiber,将其赋值给nextUnitOfWork,赋值之后performUnitOfWork就开始执行,这个函数需要处理三件事

  1. 添加这个节点到真实dom
  2. 创建当前节点的下一个fiber
  3. 赋值下一个工作单元

为什么是这种数据结构,这种结构的主要目的就是便于查找下一个工作单元,所以这里列出当前节点的父节点、子节点、同级节点

当完成一个fiber的工作的时候,如果它有子节点,则进行子节点的工作单元

所以root之后,下一个是div fiber,再下一个是h1 fiber

当没有子节点,则查看是否有兄弟节点,所以从p到a

那既没有子节点,也没有兄弟节点怎么办?那就去找父级元素,然后父母的兄弟,没有兄弟继续向上,直到根元素root,如果到达root,则说明我们已经完成了渲染的所有工作

接下来我们用代码实现一下

之前我们使用了render函数来进行渲染,需要改造一下,通过createDom这个方式来执行对应的逻辑,而createDom中,函数参数应该是每一个fiber节点

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function createDom(fiber){
  const dom = fiber.type === 'TEXT_ELEMENT' ? document.createTextNode('') : document.createElement(fiber.type)
  
  const isProperty = key => key !== 'children'
  Object.keys(ele.props).filter(isProperty).forEach(name => {
    dom[name] = ele.props[name]
  })
  return dom
}

在render函数中,我们需要设置nextUnitOfWork为根节点

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function render(element, container){
  nextUnitOfWork = {
    dom: container,
    props: {
      children: [element]
    }
  }
}

然后当浏览器有空闲时间的时候,便开始执行workLoop,执行performUnitOfWork方法,然后从根节点root开始,按照上述逻辑渲染每一个节点

performUnitOfWork这个方法当中需要做什么操作呢?上面我们已经提过了

  1. 参数fiber传入,将当前fiber节点转换成真实dom
  2. 创建一个新的fiber节点
  3. 返回下一个工作单元

我们来实现一下

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function performUnitOfWork(fiber){
  // 查看当前fiber是否已经生成dom
  if(fiber.dom){
    fiber.dom = createDom(fiber)
  }
  // 存在父节点则挂载当前节点
  if(fiber.parent){
    fiber.parent.dom.appendChild(fiber.dom)
  }
  // 创建子节点fiber
  const elements = fiber.props.children
  let index = 0
  let prevSibling = null
  
  // 然后我们将其添加到fiber树当中,将其设置为子节点或者兄弟节点
  while(index < elements.length){
    const element = elements[index]
    const newFiber = {
      type: element.type,
      props: element.props,
      parent: fiber,
      dom: null
    }
    if(index === 0){
      fiber.child = newFiber
    }else{
      prevSibling.sibling = newFiber
    }
    
    prevSibling = newFiber
    index++
  }
  
  // 搜索逻辑
  if(fiber.child){
    return fiber.child
  }
  let nextFiber = fiber
  while(nextFiber){
    if(nextFiber.sibling){
      return nextFiber.sibling
    }
    nextFiber = nextFiber.parent
  }
}

这就是我们整个performUnitOfWork函数

render和commit阶段

到这里,我们还有一个问题,工作单元目前是一个一个小的元素节点,也就是我们的真实dom需要一个一个添加到页面中。在这个过程中,浏览器可以随时打断我们执行的渲染,这个时候很有可能就会发生用户看到的是某一个小片段,这显然是有问题的

所以在这个performUnitOfWork函数中,我们需要修改这块代码,因为这里直接就会将dom插入到对应的节点中

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
if(fiber.parent){
  fiber.parent.dom.appendChild(fiber.dom)
}


我们需要定义一个wipRoot的变量,表示work in progress root,然后将它的引用地址复制给nextUnitOfWork


let wipRoot = null
let currentRoot = null

function render(element, container){
  wipRoot = {
    dom: container,
    props: {
      children: [element]
    },
    alernate: currentRoot
  }
  nextUnitOfWork = wipRoot
}

这样一旦我们完成整个工作单元,完成的条件就是没有根节点,我们就commit整个fiber tree到真实dom

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// workLoop函数中,需要增加commitRoot时机
function workLoop(deadline) {
  let shouldYield = false
  while(nextUnitOfWork && !shouldYield){
    nextUnitOfWork = performUnitOfWork(nextUnitOfWork)
    shouldYield = deadLine.timeRemaining() < 1
  }
  
  if(!nextUnitOfWork $$ wipRoot){
    commitRoot()
  }
  
  requestIdleCallback(workLoop)
}

function commitRoot(){
  commitWork(wipRoot.child)
  currentRoot = wipRoot
  wipRoot = null
}

function commitWork(fiber){
  if(!fiber) return
  const domParent = fiber.parent.dom
  domParent.appendChild(fiber.dom)
  commitWork(fiber.child)
  commitWork(fiber.sibling)
}

Reconciliation

到现在我们只是向dom添加了对应的内容,如果更新或着删除节点该怎么做呢?

我们需要将我们在渲染函数上接收到的元素,与提交给dom的最后一个fiber树进行比较

因此,我们需要在完成提交后保存对我们提交给dom的最后一个fiber树的引用

我们将performUnitOfWork中的这段代码进行替换

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
// if(fiber.parent){
//   fiber.parent.dom.appendChild(fiber.dom)
// }

const elements = fiber.props.children
reconcileChildren(fiber, elements)

这里我们将协调旧的fiber

代码语言:javascript
代码运行次数:0
运行
AI代码解释
复制
function reconcileChildren(wipFiber, elements) {
  let index = 0
  // 旧节点,上次渲染的内容
  let oldFiber =
    wipFiber.alternate && wipFiber.alternate.child
  let prevSibling = null
  
  // element是我们要渲染的内容
  elements.forEach((element, index) => {
    let newFiber = null
    const sameType = oldFiber && element && oldFiber.type === element.type
    
    // 如果旧的 fiber 和新的元素有相同的类型,我们可以保留 DOM 节点并用新的 props 更新它
    if(sameType){
      newFiber = {
        type: oldFiber.type,
        props: element.props,
        dom: oldFiber.dom,
        parent: wipFiber,
        alternate: oldFiber,
        effectTag: 'UPDATE'
      }
    }
    
    // 如果类型不同并且有一个新元素,则意味着我们需要创建一个新的 DOM 节点
    if(!sameType && element){
      newFiber = {
        type: element.type,
        props: element.props,
        dom: null,
        parent: wipFiber,
        alternate: null,
        effectTag: "PLACEMENT",
      }
    }
    
    // 如果类型不同并且有旧fiber,我们需要删除旧节点
    if (oldFiber && !sameType) {
      oldFiber.effectTag = "DELETION"
      deletions.push(oldFiber)
    }
  })
} 

之后就是需要根据这个逻辑去改造对应的逻辑处理部分,这里不详细的说明了,之后我会将源码放出来,感兴趣可以去看,这块要细讲的话内容过多

这就是整个节点更新操作删除的简单diff

总结

上面就是整个MiniReact的源码,参考自 https://pomb.us/build-your-own-react/

当然原文要比我这个好看的多,但是还是想拿出来分享一下

如果您在真实的 React 应用程序中的一个函数组件中添加一个断点,调用堆栈应该会显示:

  • workLoop
  • performUnitOfWork
  • updateFunctionComponent

我们没有包含很多 React 功能和优化,因为这是一些细致内容

我们在渲染阶段遍历整棵树,实际 React 会遵循一些提示和启发式方法来跳过没有任何变化的整个子树

我们还在提交阶段遍历整棵树。但 React 保留一个链表,其中只包含有影响的fiber,并且只访问这些fiber

每次我们构建一个新的正在进行的工作树时,我们都会为每个fiber创建新对象。 React 从以前的树中回收fiber

在渲染阶段接收到新的更新时,它会丢弃正在进行的工作树并从根部重新开始。 React 使用到期时间戳标记每个更新,并使用它来决定哪个更新具有更高的优先级

等等很多不一样的地方,但是主要的思想就是这些,如果你有什么问题或者想法,欢迎评论

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2023-01-13,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 FE情报局 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
暂无评论
推荐阅读
react源码解析19.手写迷你版react
react源码解析19.手写迷你版react 视频课程(高效学习):进入课程 课程目录: 1.开篇介绍和面试题 2.react的设计理念 3.react源码架构 4.源码目录结构和调试 5.jsx&核心api 6.legacy和concurrent模式入口函数 7.Fiber架构 8.render阶段 9.diff算法 10.commit阶段 11.生命周期 12.状态更新流程 13.hooks源码 14.手写hooks 15.scheduler&Lane 16.concurrent模式 17.contex
全栈潇晨
2021/06/24
8120
【React进阶-3】从零实现一个React(下)
这篇文章给大家介绍一下我们如何自己去实现一个类似于React这样的框架,当然,我们并不会去实现React里面所有的内容,只是去将React基础性的功能实现一遍,让大家对React的认识更加的深入。因为篇幅有限,所以我将这篇文章拆分成了上、下两部分,此文是下篇。
X北辰北
2022/02/21
7590
【React进阶-3】从零实现一个React(下)
手写简易版 React 来彻底搞懂 fiber 架构
React 16 之前和之后最大的区别就是 16 引入了 fiber,又基于 fiber 实现了 hooks。整天都提 fiber,那 fiber 到底是啥?它和 vdom 是什么关系?
神说要有光zxg
2022/03/03
8510
手写简易版 React 来彻底搞懂 fiber 架构
实现一个小而全的React
我们需要一个可以转换 jsx 的 vanilla js 环境,使用 vite 可以很方便设置好我们的开发环境
玖柒的小窝
2021/10/06
5440
实现一个小而全的React
手写系列-实现一个铂金段位的React
为什么是铂金呢,因为和王者还有很远的距离。本文仅实现简单版本的 React,参考 React 16.8 的基本功能,包括虚拟 DOM、Fiber、Diff 算法、函数式组件、hooks 等。
winty
2021/07/27
9060
从零开始的 React 再造之旅
https://segmentfault.com/a/1190000021689852
ConardLi
2020/02/24
8850
从零开始的 React 再造之旅
怎样徒手写一个React
下面先实现一个最简单的页面渲染,快速了解 JSX、React、DOM 元素的联系。
helloworld1024
2022/10/13
6700
从实现一个React到深度理解React框架核心原理
这篇文章循序渐进地介绍实现以下几个概念,遵循本篇文章基本就能搞懂为啥需要fiber,为啥需要commit和phases、reconciliation阶段等原理。本篇文章又不完全和原文一致,这里会加入我自己的一些思考,比如经过performUnitOfWork处理后fiber tree和element tree的联系等。
夏天的味道123
2022/10/17
6160
React核心技术浅析
这段代码的意思是通过 ReactDOM.render() 方法将 h1 包裹的JSX元素渲染到id为“root”的HTML元素上. 除了在JS中早已熟知的 document.getElementById() 方法外, 这段代码中还包含两个知识点:
夏天的味道123
2022/09/26
1.7K0
手写React的Fiber架构,深入理解其原理
熟悉React的朋友都知道,React支持jsx语法,我们可以直接将HTML代码写到JS中间,然后渲染到页面上,我们写的HTML如果有更新的话,React还有虚拟DOM的对比,只更新变化的部分,而不重新渲染整个页面,大大提高渲染效率。到了16.x,React更是使用了一个被称为Fiber的架构,提升了用户体验,同时还引入了hooks等特性。那隐藏在React背后的原理是怎样的呢,Fiber和hooks又是怎么实现的呢?本文会从jsx入手,手写一个简易版的React,从而深入理解React的原理。
蒋鹏飞
2020/10/15
1.7K1
手写React的Fiber架构,深入理解其原理
react fiber 到底有多细
Fiber 是对 React 核心算法的重构,facebook 团队使用两年多的时间去重构 React 的核心算法,在 React16 以上的版本中引入了 Fiber 架构,极大的提高了大型react项目的性能,也激发了我对其实现的好奇。在研究源码的过程中,能发现很多比较细的点,有任务单元拆分的细,有任务调度、双缓冲、节点复用等优化的细,都非常值得我们学习,接下来就带大家看看react fiber 到底有多细。
有赞coder
2021/05/14
8030
react fiber 到底有多细
【React进阶-2】从零实现一个React(上)
这篇文章给大家介绍一下我们如何自己去实现一个类似于React这样的框架,当然,我们并不会去实现React里面所有的内容,只是去将React基础性的功能实现一遍,让大家对React的认识更加的深入。因为篇幅有限,所以我将这篇文章拆分成了上、下两部分,此文是上篇。
X北辰北
2022/02/21
1.3K0
【React进阶-2】从零实现一个React(上)
这可能是最通俗的 React Fiber 打开方式
作者:荒山 https://juejin.im/post/5dadc6045188255a270a0f85
Nealyang
2019/10/24
2.3K1
这可能是最通俗的 React Fiber 打开方式
读懂React原理之调和与Fiber
Fiber 架构是React16中引入的新概念,目的就是解决大型 React 应用卡顿,React在遍历更新每一个节点的时候都不是用的真实DOM,都是采用虚拟DOM,所以可以理解成fiber就是React的虚拟DOM,更新Fiber的过程叫做调和,每一个fiber都可以作为一个执行单元来处理,所以每一个 fiber 可以根据自身的过期时间expirationTime,来判断是否还有空间时间执行更新,如果没有时间更新,就要把主动权交给浏览器去渲染,做一些动画,重排( reflow ),重绘 repaints 之类的事情,这样就能给用户感觉不是很卡。
xiaofeng123aa
2022/10/03
4650
这可能是最通俗的 React Fiber 打开方式
写一篇关于 React Fiber 的文章, 这个 Flag 立了很久,这也是今年的目标之一。最近的在掘金的文章获得很多关注和鼓励,给了我很多动力,所以下定决心好好把它写出来。我会以最通俗的方式将它讲透, 因此这算是一篇科普式的文章。不管你是使用React、还是Vue,这里面的思想值得学习学习!
前端劝退师
2019/12/02
6220
由浅入深React的Fiber架构
JavaScript是单线程运行的。在浏览器环境中,他需要负责页面的JavaScript解析和执行、绘制、事件处理、静态资源加载和处理。而且只能一个任务一个任务的执行,如果其中某个任务耗时很长,那后面的任务则执行不了,在浏览器端则会呈现卡死的状态。
Careteen
2022/02/14
1.8K0
由浅入深React的Fiber架构
React源码之深度理解diff算法
上一章中 react 的 render 阶段,其中 begin 时会调用 reconcileChildren 函数, reconcileChildren 中做的事情就是 react 知名的 diff 过程,本章会对 diff 算法进行讲解。
goClient1992
2022/12/09
4310
React.createElement和ReactDom.render方法简单思路
实际上,JSX 仅仅只是 React.createElement(component, props, ...children) 函数的语法糖,因此,使用 JSX 可以完成的任何事情都可以通过纯 JavaScript 完成。 例如,用 JSX 编写的代码: class Hello extends React.Component { render() { return <div>Hello {this.props.toWhat}</div>; } } ReactDOM.render( <H
刘嘿哈
2022/10/25
3080
【Fiber】: [转]React 为什么使用链表遍历 Fiber 树
To educate myself and the community, I spend a lot of time reverse-engineering web technologies and writing about my findings. In the last year, I’ve focused mostly on Angular sources which resulted in the biggest Angular publication on the web — Angular-In-Depth. Now the time has come to dive deep into React. Change detection has become the main area of my expertise in Angular, and with some patience and a lot of debugging, I hope to soon achieve that level in React.
WEBJ2EE
2021/02/26
7470
【Fiber】: [转]React 为什么使用链表遍历 Fiber 树
【Fiber】:[译]深入解析React的新协调算法
深入研究 React 的新架构 Fiber,了解新协调算法的两个主要阶段。我们将详细了解 React 如何更新组件状态(state)、属性(props)以及如何处理子元素(children)。
WEBJ2EE
2021/02/26
6700
【Fiber】:[译]深入解析React的新协调算法
相关推荐
react源码解析19.手写迷你版react
更多 >
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档
本文部分代码块支持一键运行,欢迎体验
本文部分代码块支持一键运行,欢迎体验