React源码解析18(9)------ 实现多节点渲染【修改beginWork和completeWork】

摘要

目前,我们已经实现了单节点的,beginWork,completeWork,diff流程。但是对于多节点的情况,比如:

javascript 复制代码
<div>
	<span></span>
	<span></span>
</div>

这种情况,我们还没有处理,而这种JSX会被,转换为:

javascript 复制代码
jsxs("div", {
  children: [jsx("span", {}),jsx("span", {})]
});

之前的children就直接是一个对象jsx,因为是单节点。而现在,是通过数组的方式表示。

而这一篇,主要就是对多节点的情况进行处理,所以我们要修改一下我们的index.js文件:

javascript 复制代码
function App() {
  const [text, setText] = useState('100')
  const click1 = () => {
    setText(text + 1)
  }
  return jsx("div", {
    children: [jsx("div", {
      children: text,
      onClick: click1
    }), jsx("div", {
      children: ["text1","text2",jsx("span", {
        children: "span"
      })]
    })]
  })
}

ReactDOM.createRoot(root).render(<App />)

1.修改beginWork流程

再次回顾,beginWork流程,主要是通过ReactElement,进行创建Filber树。而之前我们只考虑了return和child的情况,并没有将sibling考虑进去。

现在我们要将sibling这个属性,加进去,让整个Filber树更加全面,所以要修改我们的reconcileChidren方法。

之前在这个方法里面,我们判断element类型的时候,有FunctionComponent,HostComponent和HostText。现在因为有了多节点,所以element也有可能是数组。

如果是数组,我们就将第一个节点继续给parent.child。剩下的节点用sibling连接起来。

这里所有的sibling的return依旧指向parent。

javascript 复制代码
function reconcileChildren(parent,element) {
  //其他代码。。。
  }else if(Array.isArray(element) && element.length > 0) {
    let child = reconcileChildren(parent, element.shift());
    let head = child;
    while(element.length > 0) {
      let sibling = reconcileChildren(parent, element.shift());
      sibling.return = parent
      child.sibling = sibling;
      child = child.sibling;
    }
    return head;
  }
  //其他代码。。。
}

那再updateHostComponent中,beginWork的递归,就不能只递归child了。sibling也要递归一下:

javascript 复制代码
function updateHostComponent(filberNode) {
  const nextChildren = filberNode.pendingProps.children;
  const newFilberNode = reconcileChildren(filberNode,nextChildren);
  filberNode.child = newFilberNode;
  newFilberNode.return = filberNode;
  beginWork(newFilberNode);
  if(newFilberNode.sibling) {
    beginWork(newFilberNode.sibling)
  }
}

还有一个问题就是,对于HostText类型的节点,因为不可能有child,所以在之前的递归流程中,并没有进行处理。

但是有了sibling之后,对于HostText类型的,也要对它的sibling进行递归。

javascript 复制代码
function updateHostText(filberNode) {
  if(filberNode.sibling) {
    beginWork(filberNode.sibling)
  }
}

export const beginWork = (nowFilberNode) => {
  switch (nowFilberNode.tag) {
	//其他代码。。。
    case HostText: {
      return updateHostText(nowFilberNode)
    }
    case FunctionComponent: {

    }
    default: {
      console.error('错误的类型')
    }
  }
}

2.处理completeWork流程

在completeWork中,我们主要就是构建离屏DOM树,然后挂载在stateNode上。对于该流程来说,我们只需要在递归的过程中,将sibling属性考虑上即可:

对于HostComponent类型:

javascript 复制代码
function completeHostComponent(filberNode) {
  const type = filberNode.type;
  const element = document.createElement(type);
  addPropsToDOM(element, filberNode.pendingProps)
  filberNode.stateNode = element;
  const parent = filberNode.return;
  if(parent && parent.stateNode && parent.tag === HostComponent) {
    parent.stateNode.appendChild(element)
  }
  completeWork(filberNode.child);
  if(filberNode.sibling) {
    completeWork(filberNode.sibling)
  }
}

对于HostText类型:

javascript 复制代码
function completeHostText(filberNode) {
  const content = filberNode.pendingProps;
  const element = document.createTextNode(content)
  filberNode.stateNode = element
  const parent = filberNode.return;
  if(parent && parent.stateNode && parent.tag === HostComponent) {
    parent.stateNode.appendChild(element)
  }
  if(filberNode.sibling) {
    completeWork(filberNode.sibling)
  }
}

这样,多节点的mount渲染,我们就已经处理完了。

相关推荐
翻滚吧键盘4 分钟前
vue绑定一个返回对象的计算属性
前端·javascript·vue.js
苦夏木禾8 分钟前
js请求避免缓存的三种方式
开发语言·javascript·缓存
超级土豆粉17 分钟前
Turndown.js: 优雅地将 HTML 转换为 Markdown
开发语言·javascript·html
秃了也弱了。23 分钟前
Chrome谷歌浏览器插件ModHeader,修改请求头,开发神器
前端·chrome
乆夨(jiuze)43 分钟前
记录H5内嵌到flutter App的一个问题,引发后面使用fastClick,引发后面input输入框单击无效问题。。。
前端·javascript·vue.js
忧郁的蛋~1 小时前
HTML表格导出为Excel文件的实现方案
前端·html·excel
小彭努力中1 小时前
141.在 Vue 3 中使用 OpenLayers Link 交互:把地图中心点 / 缩放级别 / 旋转角度实时写进 URL,并同步解析显示
前端·javascript·vue.js·交互
然我1 小时前
别再只用 base64!HTML5 的 Blob 才是二进制处理的王者,面试常考
前端·面试·html
NanLing1 小时前
【纯前端推理】纯端侧 AI 对象检测:用浏览器就能跑的深度学习模型
前端
呆呆的心1 小时前
前端必学:从盒模型到定位,一篇搞定页面布局核心 🧩
前端·css