likes
comments
collection
share

JSX如何转成react-fiber的?

作者站长头像
站长
· 阅读数 11

什么是fiber?

一个fiber本质上是一个Fiber类的实例,以下是实例中的各个属性。可以看出,每一个Fiber节点之间通过指针相互关联,并找到下一个Fiber节点。因此,所有的Fiber节点相互关联就形成了Fiber树。

// 静态 Instance

this.tag = tag  //组件类型
this.key = key 
this.elementType = null  //和type大部分时间相同,除非使用react.memo包裹函数
this.type = null //和elementType大部分时间相同
this.stateNode = null  // 对应真实dom节点

// Fiber  //链表关系
this.return=null // 关联父节点
this.child=null // 关联子节点
this.sibling=null // 关联兄弟节点
this.index=0 // 同级fiber节点,代表它们插入dom的索引

this.ref = null // 字面意思,就是ref

/*------------------------作为动态单元的属性---------------------------*/

this.pendingProps = pendingProps
this.memoizedProps = null
this.updateQueue = null
this.memoizeState = null
this.dependencies = null

this.mode = mode

// Effects // 名称中带有effect的和副作用相关,
this.effectTag = NoEffect
this.subtreeTag = NoSubtreeEffect
this.deletions = null
this.nextEffect = null

this.firstEffect = null
this.lastEffect = null

this.lanes = NoLanes // 和优先级调度有关
this.childLanes = NoLanes

this.alternate = null // 与fiber架构的双缓存机制有关

Fiber节点是如何产生的呢?

Fiber树的产生源自于JSX模板,如以下代码:

假设我们有一个简单的 React 函数组件 ExampleComponent

function ExampleComponent() {
  return (
    <div className="container">
      <h1>Hello, World!</h1>
      <p>This is an example component.</p>
    </div>
  );
}

首先,webpack编译时,Babel将其转化为普通的JS代码,在这里,React.createElement的三个参数:元素类型、属性对象和子元素。


function ExampleComponent() {
  return React.createElement(
    'div',
    { className: 'container' },
    React.createElement('h1', null, 'Hello, World!'),
    React.createElement('p', null, 'This is an example component.')
  );
}

React.createElement做了什么事情呢?

React.createElement() 是 React 中用于创建虚拟 DOM 元素的函数。它接收三个参数:类型、属性对象和子元素,然后返回一个描述该元素的 JavaScript 对象

function createElement(type, props, ...children) {
  return {
    type,
    props: {
      ...props,
      children: children.map(child =>
        typeof child === "object" ? child : createTextElement(child)
      )
    }
  };
}

function createTextElement(text) {
  return {
    type: "TEXT_ELEMENT",
    props: {
      nodeValue: text,
      children: []
    }
  };
}

上述代码是一个简化版的示例,实际的 React.createElement() 实现还包含其他功能,例如处理 keyref 等特殊属性,以及一些性能优化。以下是编译后的产物,可以认为是vNode

{
  "type": "div",
  "props": {
    "className": "container",
    "children": [{
      "type": "h1",
      "props": {
        "children": [{
          "type": "TEXT_ELEMENT",
          "props": {
            "nodeValue": "Hello, World!",
            "children": []
          }
        }]
      }
    }, {
      "type": "p",
      "props": {
        "children": [{
          "type": "TEXT_ELEMENT",
          "props": {
            "nodeValue": "This is an example component.",
            "children": []
          }
        }]
      }
    }]
  }
}
// 定义 Fiber 对象
class Fiber {
  constructor(vNode) {
    this.type = vNode.type;
    this.props = vNode.props;
    this.key = vNode.key;
    this.child = null;
    this.sibling = null;
    this.alternate = null;
    // 其他需要用到的属性和状态
  }
}

// 构建 Fiber 树
function createFiberTree(vNode) {
  const fiber = new Fiber(vNode);

  if (vNode.children) {
    let prevChildFiber = null;
    vNode.children.forEach(childVNode => {
      const childFiber = createFiberTree(childVNode);
      if (prevChildFiber === null) {
        fiber.child = childFiber;
      } else {
        prevChildFiber.sibling = childFiber;
      }
      prevChildFiber = childFiber;
    });
  }

  return fiber;
}


// 将 vNode 转化为 Fiber 结构
const fiberTree = createFiberTree(vNode);

createFiberTree 函数用于递归构建 Fiber 树,根据 vNode 的层次结构创建相应的 Fiber 对象,并将子节点和兄弟节点连接起来。 生成的Fiber节点如下

const exampleFiber = {
  type: "div",
  props: {
    className: "container",
  },
  child: Fiber { 
      type: 'h1', 
      props: { children: "Hello, World!" },
      key: null, 
      child: null, 
      sibling: Fiber { ... }, 
      alternate: null, 
  },
  sibling: null,
  return: null
};

exampleFiber.child = {
  type: "h1",
  props: { children: "Hello, World!" },
  child: null,
  sibling: null,
  return: exampleFiber
};

exampleFiber.child.sibling = {
  type: "p",
  props: { children: "This is an example component." },
  child: null,
  sibling: null,
  return: exampleFiber
};

在上述代码中,我们创建了两个子节点的 Fiber 对象,并将它们连接到父节点 exampleFiberchildsibling 属性上。通过这种方式,我们可以构建出一个简单的 Fiber 树结构。

在这里能得到的一个信息是,每一个元素都会变成一个Fiber节点。当后续这些元素关联的变量发生改变时,它又是怎样去触发更新的呢?