React基础理论概念、VirtualDOM、Fiber等的笔记

参考:

  1. https://github.com/reactjs/react-basic
  2. https://github.com/acdlite/react-fiber-architecture

React 基本理论概念

React核心前提:UI将数据投影到另一种形式的数据中,相同的输入产生相同的输入

function NameBox(name) {
  return {
    fontWeight: 'bold',
    labelContent: name
  }
}
'Sebastian Markbåge' ->
{ fontWeight: 'bold', labelContent: 'Sebastian Markbåge' };

抽象

UI可抽象为可重复使用的部分,而不会泄漏实现细节,eg:从另一个函数调用另一个函数

function FancyUserBox(user) {
  return {
     borderStyle: '1px solid blue',
    childContent: [
      'Name: ',
      NameBox(user.firstName + ' ' + user.lastName)
  }
}
{ firstName: 'Sebastian', lastName: 'Markbåge' } ->
{
  borderStyle: '1px solid blue',
  childContent: [
    'Name: ',
    { fontWeight: 'bold', labelContent: 'Sebastian Markbåge' }
  ]
};

进一步抽象组合:将两个或多个不同的抽象组合成一个新的抽象

function FancyBox(children) {
  return {
    borderStyle: '1px solid blue',
    children: children
  };
}

function UserBox(user) {
  return FancyBox([
    'Name: ',
    NameBox(user.firstName + ' ' + user.lastName)
  ]);
}

状态

UI不仅是业务逻辑状态的复制


function FancyNameBox(user, likes, onClick) {
  return FancyBox([
    'Name: ', NameBox(user.firstName + ' ' + user.lastName),
    'Likes: ', LikeBox(likes),
    LikeButton(onClick)
  ]);
}

// Implementation Details

var likes = 0;
function addOneMoreLike() {
  likes++;
  rerender();
}

// Init

FancyNameBox(
  { firstName: 'Sebastian', lastName: 'Markbåge' },
  likes,
  addOneMoreLike
);

使用副作用更新状态,在更新过程中返回下一个版本的状态

记忆化

如果我们知道该函数是纯函数,那么反复调用同一个函数就是一种浪费。我们可以创建一个函数的记忆版本,以跟踪最后一个参数和最后一个结果。这样,如果我们继续使用相同的值,就不必重新执行它。

function memoize(fn) {
  var cachedArg;
  var cachedResult;
  return function(arg) {
    if (cachedArg === arg) {
      return cachedResult;
    }
    cachedArg = arg;
    cachedResult = fn(arg);
    return cachedResult;
  };
}

var MemoizedNameBox = memoize(NameBox);

function NameAndAgeBox(user, currentTime) {
  return FancyBox([
    'Name: ',
    MemoizedNameBox(user.firstName + ' ' + user.lastName),
    'Age in milliseconds: ',
    currentTime - user.dateOfBirth
  ]);
}

什么是Virtual DOM

虚拟DOM也是一种编程理念,UI以JS对象表达并存储于内存中,通过ReactDOM等类库与真实DOM同步

Shadow DOM和Virtual DOM的区别

Shadow DOM是浏览器技术,主要用于在Web组件中封装变量和CSS
Virtual DOM是JS类库基于浏览器API实现的概念

什么是React Fiber?

React Fiber的核心作用:实现虚拟DOM可异步可中断增量式更新

主要功能:【增量渲染】:具体将渲染工作拆分成多个块并将其分散到多个帧上。

什么是调和 Reconciliation?

Reconciliation:React使用算法来比较一个树与另一颗树的差异来确定哪些部分需要更改
Update:用于渲染React应用的数据发生变化,eg:调用setState导致重新渲染你

React API核心思想:将更新视为导致整个应用重新渲染

调和 =》 虚拟DOM背后的算法

渲染React应用程序时,会生成一个描述App的节点树将其保存到内存中
之后,该树被刷新到渲染环境,在浏览器应用程序中会转换为一组DOM操作

当应用程序更新时(eg: setState)会生成一颗新的树,新树和旧树进行差异化,以计算更新渲染的应用程序所需操作

React设计 =》 调和和渲染分开

  • 调和器负责计算树的哪些部分发生变化
  • 渲染器使用该信息来实际更新渲染的应用程序

这种分离意味着 React DOM 和 React Native 可以使用自己的渲染器,同时共享 React 核心提供的同一个协调器。

Fiber 重新实现了调和器。它主要不关心渲染,尽管渲染器需要进行更改才能支持(并利用)新架构。

什么是Fiber?

Fiber的目标:使得React能够利用调度

  • 暂停工作,稍后继续
  • 对不同类型的工作分配优先级别
  • 重复使用以前完成的工作
  • 如果不再需要则中止工作

首先需要一种方法将工作分解为单元。从某种意义上说,这就是 Fiber。Fiber 代表工作单元。
React组件作为数据函数的概念

v = f(d)

渲染React应用 =》类似于调用一个函数,该函数的主体包含对其他函数的调用

eg: 计算机通过调用堆栈来跟踪程序的执行情况,执行函数时,会将新的堆栈框架添加到堆栈中
该堆栈框架代表该函数执行的工作

在处理UI时,若一次性处理过多工作会导致 动画丢帧不连贯

组件比函数具有更多具体的关注点

解决该问题的API: requestIdleCallback => 安排在空闲期间调用低优先级函数
requeestAnimationFrame安排在下一个动画帧调用高优先级函数

将渲染工作分解为增量单元 | Fiber: 可以随意中断调用堆栈并手动操作堆栈帧

React Fiber的目的:Fiber是堆栈的重新实现,专门用于React组件,单个fiber视为虚拟堆栈框架

将堆栈框架保存在内存中,需要的时候执行
除了调度之外,手动处理堆栈帧 还可以释放并发和错误边界等功能

Fiber的结构

Fiber是一个JS对象,包含组件和其输入输出的信息

一个Fiber对应一个堆栈框架,也对应一个组件的一个实例

Fiber是如何工作的? https://www.facebook.com/groups/2003630259862046/permalink/2054053404819731/

Fiber的关键字段

type和key

Fiber的type和key的作用 和 React元素的作用相同
当从Element创建Fiber时,type和key会直接复制

Fiber的type: 描述对应的组件
对于复合组件,类型是函数或类组件本身
对于宿主组件(div、span)等,类型是字符串
key和type在协调期间可用于确定Fiber是否可以重复使用

child和sibling

child =》 指向子Fiber

eg:
function Parent() {
  return <Child/>
}

sibling =》指向兄弟Fiber

function Parent() {
  return [<Child1/>, <Child2/>]
}

子Fiber形成一个单链表,头部是第一个子Fiber

return

返回Fiber是程序在处理完当前Fiber后返回到的Fiber
在概念上和堆栈帧的返回地址相同 =》可认为是父Fiber

pendingProps和memoizedProps

props是函数的参数
fiber的参数pendingProps在执行开始时设置
memoizedProps在执行结束时设置
当输入pendingProps等于memoizedProps,表明当前Fiber之前的输出可重复使用

pendingWorkPriority

表明该Fiber代表的工作的优先级的数字。
ReactPriorityLevel模块列出不同的优先级和代表的含义
数字越大优先级越低

function matchesPriority(fiber, priority) {
  return fiber.pendingWorkPriority !== 0 &&
         fiber.pendingWorkPriority <= priority
}

调度程序使用优先级字段来搜索下一个要执行的工作单元

在任何时候,一个组件实例最多存在两个与之对应的Fiber

  • 当前已刷新的Fiber
  • 正在进行中的Fiber(内存中的替代品

cloneFiber会尝试重用Fiber,最大限度减少分配

每个Fiber最终都有输出,输出仅由宿主组件在叶子节点创建
输出随后沿树向上传输

最终所有的输出内容都会提供给渲染器,渲染器将其刷新到渲染环境中
渲染器负责定义如何创建和更新输出

posted @ 2024-12-27 20:05  Felix_Openmind  阅读(44)  评论(0)    收藏  举报
*{cursor: url(https://files-cdn.cnblogs.com/files/morango/fish-cursor.ico),auto;}