手写Mini React-01 虚拟DOM

776 阅读2分钟

什么是虚拟DOM

只要可以用来描述Dom的数据结构都是虚拟Dom

换句话说 虚拟Dom可以是对象,数组,字符串...

React中JSX和虚拟DOM

  function App() {
    return (
      <div>
        <p>Hello</p>
      </div>
    )
  }

JSX只是React 虚拟Dom的一个语法糖

  <div>222</div>

会被Babel编译为:

import { jsx as _jsx } from "react/jsx-runtime";
/*#__PURE__*/_jsx("div", {
  children: "222"
});

最终返回一个对象, 返回的这个对象就是React的虚拟Dom

console.log(<div>222</div>)

打印出来内容如下

{
    $$typeof: Symbol(react.element),
    type: "div",
    key: null,
    ref: null,
    props: {
        children: "222"
    },
    "_owner": null,
    "_store": {}
}

React 的虚拟Dom其实就是一个普通对对象,

  • $$typeof是一个用标识虚拟Dom的符号
  • type 代表虚拟Dom对应的真实Dom类型 也有可能时React组件, Portal, Fragment...
  • key 就是props上的key, 这个属性用来在Diff是判断是否需要更新
  • ref 就是绑定的ref(React.useRef,React.createRef)
  • props 就是给组件的传的props

可以定义一下虚拟Dom的类型

type VNode = {
  $$typeof: Symbol;
  type: string;
  key: string | null;
  ref: unknow | null;
  props: any
}

虚拟Dom和Fiber

上面说到只要时能够描述真实Dom的数据结构都是可被定义为虚拟Dom, 很明显Fiber也是虚拟Dom

在React 16之后放弃Stack架构使用Fiber架构, 为了区分我们使用VNode代表老版本的虚拟Dom, Fiber代表新的虚拟Dom

并不是说新版本的React就不存在VNode, babel仍然会将jsx编译为VNode 然后根据VNode生成Fiber, 至于为什么babel不直接将jsx编译为Fiber就不得而知了

可以在浏览器中打印Fiber的结构

image.png

可以看出比VNode的属性要多很多

简单介绍下几个比较重要的属性

  • key 同 VNode
  • type 同 VNode
  • memoizedProps 记录之前的props (防止组件更新, props丢失)
  • memoizedState 记录之前的state (防止组件更新, state被重置)
  • flags 需要做的操作 替换(新增,插入,移动) 删除 更新
  • child 子Fiber节点
  • stateNode 对应的真实Dom
  • alternate 之前的Fiber
  • return 父级Fiber
  • sibling 兄弟Fiber

Fiber使用链表结构来表示每个Fiber的关系

例如:

<div>
  <h1>Hi</h1>
  <p>Some Text</p>
</div>

会被表示为

image-1.png

这里大家应该对虚拟DOM和Fiber有了基础的认识 后面我们来实现创建的Fiber的方法