当前位置: 首页 > news >正文

React源码解析18(5)------ 实现函数组件【修改beginWork和completeWork】

摘要

经过之前的几篇文章,我们实现了基本的jsx,在页面渲染的过程。但是如果是通过函数组件写出来的组件,还是不能渲染到页面上的。
所以这一篇,主要是对之前写得方法进行修改,从而能够显示函数组件,所以现在我们在index.js文件中,修改一下jsx的写法。修改成函数组件:

import jsx from '../src/react/jsx.js'
import ReactDOM from '../src/react-dom/index'const root = document.querySelector('#root');function App() {return jsx("div", {ref: "123",children: jsx("span", {children: "456"})});
}ReactDOM.createRoot(root).render(<App />)

这里因为需要使用我们自己的jsx方法。所以在App里面返回的依旧是通过之前的方式进行调用。

1.修改reconcileChildren方法

我们来回忆一下,在beginWork阶段,我们主要是通过ReactElement,创建FilberNode。而reconcileChildren,就是创建FilberNode的方法。

在之前我们只处理了HostText类型和HostComponent类型,所以在这个方法里面,我们要对函数类型进行兼容,而作为函数组件的ReactElment,它最显而易见的特点就是type的值是一个函数。

例如上面的App组件,对应的ReactElement的type就是App。所以我们可以通过type来判断组件的类型:

function reconcileChildren(element) {let tag;if(typeof element.type === 'function') {tag = FunctionComponent}//其他代码console.log(filberNode)return filberNode
}

我们打印一下看看,这个函数组件是否满足预期:

在这里插入图片描述

2.updateFunctionComponent方法

现在有了tag为FunctionComponent类型的FilberNode,在beginWork里面,我们就要对这个类型的FilberNode进行处理:

function beginWork(nowFilberNode) {switch (nowFilberNode.tag) {//其他代码case FunctionComponent: {return updateFunctionComponent(nowFilberNode)}//其他代码}
}

现在我们来实现updateFunctionComponent方法。
之前对于HostComponent类型的FilberNode,它的子节点其实就是它对应的ReactElement。

但是对于函数类型的FilberNode,我们想一下不就是它自己的返回值嘛?所以我们直接调用这个函数就能拿到它的子FilberNode了。

function updateFunctionComponent(filberNode) {const nextChildren = filberNode.type();const newFilberNode = reconcileChildren(nextChildren);filberNode.child = newFilberNode;newFilberNode.return = filberNode;beginWork(newFilberNode)
}

2.修改completeWork方法

对于completeWork方法, 它的主要作用(目前)是给对应的FilberNode增加stateNode,而函数组件并没有自己对应的StateNode,所以直接继续递归就可以了:

export const completeWork = (filberNode) => {const tag = filberNode.tagswitch (tag) {//其他代码。。。case FunctionComponent: {completeWork(filberNode.child)}}
}

3.修改commitWork方法

对于之前的commitWork,我们是直接将最外层的FilberNode的stateNode挂载了容器上,现在由于最外层的可能是FunctionComponent,它是没有自己的stateNode的。所以我们要找到具有stateNode的最外层FilberNode。

import { HostComponent } from "./filberNode";export function commitWork(filberRootNode) {const container = filberRootNode.container;let node = filberRootNode.finishedWork;while( node.tag !== HostComponent ){node = node.child}container.appendChild(node.stateNode)
}

OK,经过上面的修改,我们的App组件也可以正常渲染了。

http://www.lryc.cn/news/130243.html

相关文章:

  • vscode ssh 远程 gdb 调试
  • 云原生 AI 工程化实践之 FasterTransformer 加速 LLM 推理
  • PHP酒店点菜管理系统mysql数据库web结构apache计算机软件工程网页wamp
  • 【面试复盘】知乎暑期实习算法工程师二面
  • 内网穿透和服务器+IP 实现公网访问内网的区别
  • JAVA权限管理 助力企业精细化运营
  • 金融语言模型:FinGPT
  • LeetCode--HOT100题(30)
  • Springboot 实践(3)配置DataSource及创建数据库
  • 【问题整理】Ubuntu 执行 apt-get install xxx 报错
  • Java课题笔记~ SpringBoot简介
  • 一种基于springboot、redis的分布式任务引擎的实现(一)
  • 基于IDE Eval Resetter延长IntelliJ IDEA等软件试用期的方法(包含新版本软件的操作方法)
  • RocketMQ消费者可以手动消费但无法主动消费问题,或生成者发送超时
  • 【数据库系统】--【2】DBMS架构
  • 第三章 图论 No.13拓扑排序
  • 喜报 | 擎创再度入围IDC中国FinTech 50榜单
  • 【C++ 记忆站】引用
  • Hlang--用Python写个编程语言-变量的实现
  • 多维时序 | MATLAB实现PSO-CNN-BiLSTM多变量时间序列预测
  • 实现Java异步调用的高效方法
  • 批量提取文件名到excel,详细的提取步骤
  • C#中的泛型约束可以用在以下几个地方?
  • Linux Vm上部署Docker
  • ubuntu bind dns服务配置
  • 安卓的代码加固和其他安全问题
  • 关于Linux Docker springboot jar 日志时间不正确 问题解决
  • 提高批量爬虫工作效率
  • E96系列电阻阻值和代码、乘数对照表
  • 基于CentOS7.9安装部署docker(简洁版)