【催学社mini-react游戏副本】学习笔记和心得

文章讲述了作者七天内逐步实现mini-react框架,涉及vdom、jsx的使用,任务调度器、fiber架构的应用,以及如何处理状态管理和副作用函数。通过解决性能问题和优化更新逻辑,提升用户体验。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

项目github链接

第一天

实现最简mini-react

目标:在页面中呈现hi-mini-react字符,api和react保持一致。

采用渐进式

  • 先从简单的入手,慢慢完善丰满。

v0.1

直接用利用dom api,在根结点中插入文本节点。

v0.2

变得可复用
用js对象描述节点,也就是vdom。
根据vdom用dom api创建元素。

使用工厂函数创建vdom。
写一个render函数,将vdom转换成真实dom,并挂载到页面上。

修改成类似react的api风格

jsx

问题:如何使用jsx?
目标:使用jsx

利用vite实现jsx的解析

jsx最终会转换成React.createElement
注意要提前导入React

第二天

实现任务调度器

问题

dom树特别大,导致渲染卡顿

js是单线程的,进行大量计算的时候,会阻塞浏览器渲染页面

解决思路

把大任务拆分到多个task里面完成

采用分治思想,把大任务拆分成多个小任务,让小任务在空闲时间执行,这样可以避免一次性进行大量计算导致阻塞。

实现

采用requestIdleCallback分帧运算
requestIdleCallbackapi可以实现。

插入一个函数,在空闲时间执行。
函数执行时,会接收一个参数,IdleDeadline,可以拿到还剩多少空闲时间,如果空闲时间还够的话,就接着执行任务,直到空闲时间小于1。

新的问题,如何拆分任务,控制渲染,又如何恢复?

实现fiber架构

问题

  • 如何做到每次只渲染几个节点?
  • 在下次执行的时候依然从之前的位置执行?

解决思路

一次只渲染一个节点,依次渲染。
采用链表的方式把任务串起来。
把dom树转换 成链表结构。

  • child
  • sibling
  • uncle
    使用任务调度器,按照顺序渲染节点。

两种方式:

  • 执行之前,把树转换成链表
  • 边转换边调度(更优)

渲染当前节点A时要做的事:

  • 生成真实dom,赋上对应属性
  • 转换成链表
  • A相关信息都初始化。
    A的子节点是什么,子节点的下一个兄弟节点是什么。
  • 渲染结束时返回下一个节点。

第三天

实现统一提交

问题

中途有可能没空余时间,用户会看到渲染一半的dom。

解决思路

计算结束后,将dom统一提交。

支持function component

问题

如何支持function component

解决思路

把fc当成一个盒子

  1. 开箱
    目前createDom无法解析type是function的节点。
    由于函数的返回值vdom,是可以解析的。
    所以我们要调用函数拿到vdom,可以看作是一个开箱的过程。把拿到的vdom作为函数组件节点的children

要注意,函数组件节点本身是没有dom的,所以在统一提交阶段要特殊处理。

  1. props
    开箱的时候,把props传入进去。

第四天

复习前面所学。

第五天

实现事件绑定

在jsx中绑定一个事件,其实就是传递一个属性,在props中。
事件的标志就是on开头,在处理属性的时候绑定事件即可。

实现更新

更新时需要对比新旧fiber,在构建新fiber链表时,用alternate属性关联旧fiber,effectTag标识新建还是更新。在操作dom阶段,比较新旧props,根据fiber上的effectTag区分更新还是挂载。

第六天

实现更新中的创建和删除

  • type不一致,删除旧的,创建新的。
    把要删除的节点收集起来。在commitWork时,统一处理删除逻辑。
    对于函数组件的删除要特殊处理,因为函数组件的fiber.domnull
  • 新的比老的短,多出来的节点需要删除掉。
    老的长时,新的遍历先结束,所以要把老的剩余部分遍历收集起来,删掉。
  • 根据case不断完善。
  • 解决edgecase
    • 画图分析
    • debug

优化更新逻辑

问题

更新子组件,不相关组件也会重新执行,浪费性能。

解决思路

之前每次更新都是从根节点开始,导致要遍历整棵树。

  • 开始节点
    触发更新的那个节点。
  • 结束节点
    在进行到它的兄弟节点时停止。

第七天

实现useState

  • 在一个fc中,state按照顺序存在数组中。
  • 将状态数组存在fiber
  • 每次执行fc时,拿到旧fiber上的状态数组,按照顺序读取状态,并存在新的fiber上。
  • setState每次都是重新创建的,由于闭包的原因,state也是最新的。
  • 每次调用setState后,先收集到queue中,最后统一执行更改state操作,优化视图渲染次数。
  • state不变时不更新

第八天

实现useEffect

  • effectHooks存在fiber上。
  • 每一个effectHook会有callbackdepscleanup属性。
  • 在dom挂载后,遍历fiber,依次执行所有cleanup,在依次执行callback。

学习心得

确定目标,小步骤开发,一次只专注一件事情,先实现功能,再重构优化。
遇到问题先画图或debug理清思路,找到问题的原因再尝试解决。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值