React16源码: React中Fiber对象的源码实现

2024-01-09 01:28

本文主要是介绍React16源码: React中Fiber对象的源码实现,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

关于 Fiber 对象

  • FiberRoot里面,它也会为我们去创建的一个对象叫做 Fiber
  • 在 React16 之后, 非常核心,非常重要的一个东西
  • A. 每个 ReactElement 都会对应一个 Fiber 对象
  • B. 它会记录节点的各种状态
    • 比如,class component,它的state和props
    • 这些东西是记录在 Fiber 对象上面的
    • 在 Fiber 更新之后才会更新到 class component 上面的 this.state, this.props 里面
    • 并不是通过 class component 自己去调理的这个过程
    • 这些过程都是在 Fiber 上面进行操作的,只是在更新了这个节点之后
    • 它才会把这个属性放到this上面,因此也给了react实现 hooks 一个方便
    • 因为hooks是用在function component里面的,里面没有this
    • 我们本身记录state还有props都不是在class component的对象上面,而是在 Fiber 上面
    • 我们有能力记录这个状态之后,也可以让function component更新的过程当中去拿到这个更新之后的state
    • 所以Fiber有一个非常重要的作用,就是记录节点的各种状态
  • C. 串联整个应用
    • 在 ReactElement 中,通过 props.children 属性把整个应用串联起来
    • 每一个节点都可以通过一个属性去拿到它的子节点
    • 在 Fiber 里面,它也是有这么一个能力来帮助我们记录整个应用的一个树形结构的一个状态,把每一个节点给它串联起来
    • 在 Fiber 里面它是如何进行一个串联的呢?需要先回顾一下 ReactElement 的串联方式, 结合前文中的举例,如下
                  App|render() return|div/ \/   \children[0]  children[1]/       \/         \/           \Input          List|               \
      render() return     render() return |                 \input        (span  span  span  button)
      
    • 上面就是 ReactElement 基于 render() 函数 return 了子节点,由此构建的树形结构
    • Fiber 里面也有这个能力记录整个应用的树形结构和状态,把每个节点串联起来
                -----current-----> FiberRoot                     RootFiber<---stateNode-----    |   |child  |↓App|child|↓|div/ \/   \child   child/       \/         \/           \Input-sibling-> List|               \child            child|                \↓                 \input               span --sibling--> span --sibling--> span --sibling--> button
      
    • 被首先创建的 FiberRoot 有一个 current 属性,指向一个 Fiber对象,我们叫做 RootFiber
    • 因为 FiberRoot 在 ReactDOM.render 时,接受了 一个参数是 App
    • App 这个 ReactElement 它对应的Fiber对象就是 RootFiber 的 child
    • App 的 child 就是 div 节点,因为它的 render 函数渲染出来之后就是一个 div 的唯一子节点
    • 这个 div 接收到的 props.children 是一个数组,这个数组的第一个节点会作为它的 child, 其指向 Input 组件对应的 Fiber对象
    • List 也是作为 div的 props.children 的一项,它是 Input 对应Fiber对象的 sibling 兄弟节点
    • 也就是说,每个节点只会存储它的第一个子节点,不会把它的子节点都存放在一起,通过上述单项的指向来进行存储
    • 对于 Input 组件来说,它的 child 就是其 render 函数 return 的一个 input 原生标签
    • 对于 List 组件来说,它返回的是一个数组,它的第一个子节点就是 span, 剩下的兄弟节点通过 sibling 来连接
    • 而每个子节点都会有一个 return 属性指向自己的父节点,上述图示中并没有标示出来
    • 我们进行节点的查找就会非常方便,只需要通过 child 一路向下查找,直接到叶子节点
    • 基于这种方式来遍历整个应用,即通过react的这种数据结构,把整个 Fiber树给它串联起来,提供给我们一个方便高效的遍历方式
    • 现在看下 Fiber 的属性,源码在: https://github.com/facebook/react/blob/v16.6.0/packages/react-reconciler/src/ReactFiber.js
      // A Fiber is work on a Component that needs to be done or was done. There can
      // be more than one per component.
      export type Fiber = {|// These first fields are conceptually members of an Instance. This used to// be split into a separate type and intersected with the other Fiber fields,// but until Flow fixes its intersection bugs, we've merged them into a// single type.// An Instance is shared between all versions of a component. We can easily// break this out into a separate object to avoid copying so much to the// alternate versions of the tree. We put this on a single object for now to// minimize the number of objects created during the initial render.// Tag identifying the type of fiber.tag: WorkTag, // 标记不同的组件类型,有原生dom节点的组件, 有 class component, function component, 各种各样的组件都有对应的类型// Unique identifier of this child.key: null | string, // ReactElement 里面的key// The value of element.type which is used to preserve the identity during// reconciliation of this child.elementType: any, // ReactElement.type, 就是调用 createElement 的第一个参数// The resolved function/class/ associated with this fiber.type: any, // 异步组件 resolved 之后返回的内容, 一般是 function 或 class// The local state associated with this fiber.stateNode: any, // 跟当前Fiber相关的本地状态,在浏览器环境中就是DOM节点,对应节点实际的实例,比如 class component 对应 class 的实例, dom组件对应dom节点的实例,function component 没有实例,就没有 stateNode, 有了它在应用更新完成后,就可以把 最新的 state,props 等放到节点上// Conceptual aliases// parent : Instance -> return The parent happens to be the same as the// return fiber since we've merged the fiber and instance.// Remaining fields belong to Fiber// The Fiber to return to after finishing processing this one.// This is effectively the parent, but there can be multiple parents (two)// so this is only the parent of the thing we're currently processing.// It is conceptually the same as the return address of a stack frame.return: Fiber | null,// Singly Linked List Tree Structure.child: Fiber | null,sibling: Fiber | null,index: number,// The ref last used to attach this node.// I'll avoid adding an owner field for prod and model that as functions.ref: null | (((handle: mixed) => void) & {_stringRef: ?string}) | RefObject, // ref 属性// Input is the data coming into process this fiber. Arguments. Props.pendingProps: any, // This type will be more specific once we overload the tag. // 新的变动,带来的新的 props,就存在 pendingProps 属性上memoizedProps: any, // The props used to create the output. // 上一次更新结束之后的 props// A queue of state updates and callbacks.updateQueue: UpdateQueue<any> | null, // 该 Fiber 对应的组件产生的 update 会存放在这个队列里面// The state used to create the outputmemoizedState: any, // 上次渲染完成之后的 state,比如我们执行setState,会算出一个新的state,算出是要经过 updateQueue计算的, 计算完之后覆盖 memoizedState 值// A linked-list of contexts that this fiber depends onfirstContextDependency: ContextDependency<mixed> | null, // 一个列表,存放这个Fiber依赖的context// Bitfield that describes properties about the fiber and its subtree. E.g.// the ConcurrentMode flag indicates whether the subtree should be async-by-// default. When a fiber is created, it inherits the mode of its// parent. Additional flags can be set at creation time, but after that the// value should remain unchanged throughout the fiber's lifetime, particularly// before its child fibers are created.mode: TypeOfMode, // 用于描述当前Fiber和它子树的Bitfield, 共存的模式表示这个子树是否默认是异步渲染的, Fiber 被创建的时候会继承父Fiber, 其他的标识也可以在创建的时候被设置,但在创建之后不应该再被修改,特别是他的子Fiber创建之前, 对应比如: ConcurrentMode, StrictMode,// EffecteffectTag: SideEffectTag, // 副作用,用来记录 Side Effect// Singly linked list fast path to the next fiber with side-effects.nextEffect: Fiber | null, // 副作用, 单链表用来快速查找下一个 side effect// The first and last fiber with side-effect within this subtree. This allows// us to reuse a slice of the linked list when we reuse the work done within// this fiber.firstEffect: Fiber | null, // 副作用,子树中第一个 side effectlastEffect: Fiber | null, // 副作用,子树中最后一个 side effect// Represents a time in the future by which this work should be completed.// Does not include work found in its subtree.expirationTime: ExpirationTime, // 当前节点产生的更新任务的过期时间, 代表任务在未来的哪个时间点应该被完成,不包括他的子树产生的任务// This is used to quickly determine if a subtree has no pending changes.childExpirationTime: ExpirationTime, // 它的子节点如果产生更新,记录子节点的过期时间, 快速确定子树中是否有不在等待的变化// This is a pooled version of a Fiber. Every fiber that gets updated will// eventually have a pair. There are cases when we can clean up pairs to save// memory if we need to.alternate: Fiber | null, // 在Fiber树更新的过程中,每个Fiber都会有一个跟其对应的Fiber,我们称它为 current <==> workInProgress的对应关系, 在渲染完成之后他们会交换位置,在更新过程中,会根据整个Fiber对象,创建一个 workInProgress, current是当前的, workInProgress 是要进行一个更新的, 在更新完成后,workInProgress 状态会更新成一个新的,current就变成老的,最终节点渲染到 dom 上面,workInProgress 会变成current,再下一次更新到来的时候,会保持着两个对象都存在,这个在 react 中叫做 double buffer, 是用来提高性能的// Time spent rendering this Fiber and its descendants for the current update.// This tells us how well the tree makes use of sCU for memoization.// It is reset to 0 each time we render and only updated when we don't bailout.// This field is only set when the enableProfilerTimer flag is enabled.actualDuration?: number,// If the Fiber is currently active in the "render" phase,// This marks the time at which the work began.// This field is only set when the enableProfilerTimer flag is enabled.actualStartTime?: number,// Duration of the most recent render time for this Fiber.// This value is not updated when we bailout for memoization purposes.// This field is only set when the enableProfilerTimer flag is enabled.selfBaseDuration?: number,// Sum of base times for all descedents of this Fiber.// This value bubbles up during the "complete" phase.// This field is only set when the enableProfilerTimer flag is enabled.treeBaseDuration?: number,// Conceptual aliases// workInProgress : Fiber ->  alternate The alternate used for reuse happens// to be the same as work in progress.// __DEV__ only_debugID?: number,_debugSource?: Source | null,_debugOwner?: Fiber | null,_debugIsCurrentlyTiming?: boolean,
      |};
      
    • Fiber里面三个重要的属性: return, child, sibling 可以帮助把应用中的所有节点一一串联
      • return: 指向它在Fiber节点树中的 parent, 用来处理完这个节点之后,向上返回
      • child: 单链表树结构, 指向自己的第一个子节点
      • sibling: 指向自己的兄弟结构,兄弟节点的return指向同一个父节点
    • 上述 Effect 相关的属性,都是副作用,是用来标记 Dom 节点要进行那些更新的工具,以及标记是否要执行组件生命周期的内容
    • 上述 Duration 相关属性,是渲染时间相关的,和 React DEV TOOL 有相关关系
    • 其他属性,都在代码中备注

这篇关于React16源码: React中Fiber对象的源码实现的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/585494

相关文章

Spring Boot 实现 IP 限流的原理、实践与利弊解析

《SpringBoot实现IP限流的原理、实践与利弊解析》在SpringBoot中实现IP限流是一种简单而有效的方式来保障系统的稳定性和可用性,本文给大家介绍SpringBoot实现IP限... 目录一、引言二、IP 限流原理2.1 令牌桶算法2.2 漏桶算法三、使用场景3.1 防止恶意攻击3.2 控制资源

springboot下载接口限速功能实现

《springboot下载接口限速功能实现》通过Redis统计并发数动态调整每个用户带宽,核心逻辑为每秒读取并发送限定数据量,防止单用户占用过多资源,确保整体下载均衡且高效,本文给大家介绍spring... 目录 一、整体目标 二、涉及的主要类/方法✅ 三、核心流程图解(简化) 四、关键代码详解1️⃣ 设置

SpringMVC高效获取JavaBean对象指南

《SpringMVC高效获取JavaBean对象指南》SpringMVC通过数据绑定自动将请求参数映射到JavaBean,支持表单、URL及JSON数据,需用@ModelAttribute、@Requ... 目录Spring MVC 获取 JavaBean 对象指南核心机制:数据绑定实现步骤1. 定义 Ja

Nginx 配置跨域的实现及常见问题解决

《Nginx配置跨域的实现及常见问题解决》本文主要介绍了Nginx配置跨域的实现及常见问题解决,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来... 目录1. 跨域1.1 同源策略1.2 跨域资源共享(CORS)2. Nginx 配置跨域的场景2.1

Python中提取文件名扩展名的多种方法实现

《Python中提取文件名扩展名的多种方法实现》在Python编程中,经常会遇到需要从文件名中提取扩展名的场景,Python提供了多种方法来实现这一功能,不同方法适用于不同的场景和需求,包括os.pa... 目录技术背景实现步骤方法一:使用os.path.splitext方法二:使用pathlib模块方法三

Python打印对象所有属性和值的方法小结

《Python打印对象所有属性和值的方法小结》在Python开发过程中,调试代码时经常需要查看对象的当前状态,也就是对象的所有属性和对应的值,然而,Python并没有像PHP的print_r那样直接提... 目录python中打印对象所有属性和值的方法实现步骤1. 使用vars()和pprint()2. 使

CSS place-items: center解析与用法详解

《CSSplace-items:center解析与用法详解》place-items:center;是一个强大的CSS简写属性,用于同时控制网格(Grid)和弹性盒(Flexbox)... place-items: center; 是一个强大的 css 简写属性,用于同时控制 网格(Grid) 和 弹性盒(F

CSS实现元素撑满剩余空间的五种方法

《CSS实现元素撑满剩余空间的五种方法》在日常开发中,我们经常需要让某个元素占据容器的剩余空间,本文将介绍5种不同的方法来实现这个需求,并分析各种方法的优缺点,感兴趣的朋友一起看看吧... css实现元素撑满剩余空间的5种方法 在日常开发中,我们经常需要让某个元素占据容器的剩余空间。这是一个常见的布局需求

CSS Anchor Positioning重新定义锚点定位的时代来临(最新推荐)

《CSSAnchorPositioning重新定义锚点定位的时代来临(最新推荐)》CSSAnchorPositioning是一项仍在草案中的新特性,由Chrome125开始提供原生支持需... 目录 css Anchor Positioning:重新定义「锚定定位」的时代来了! 什么是 Anchor Pos

CSS中的Static、Relative、Absolute、Fixed、Sticky的应用与详细对比

《CSS中的Static、Relative、Absolute、Fixed、Sticky的应用与详细对比》CSS中的position属性用于控制元素的定位方式,不同的定位方式会影响元素在页面中的布... css 中的 position 属性用于控制元素的定位方式,不同的定位方式会影响元素在页面中的布局和层叠关