学习React18心得

学习背景

先介绍一下自己,我是一个工作了大约5~6年的前端开发,公司主要的技术其实是vue而并非是react,而我接触vue的时间大概接触了3年多,更早时间其实接触的是jquery写的项目,而半年前看到了卡颂老师的《从零实现React18》的课程,很荣信能碰到卡颂老师这门课程,他给了我很多的收获。

为什么要学习react源码?

两个方面的原因

①是为了能提升自己的武器库,在现阶段行业很内卷的情况下,自身的能力越强才越有竞争的能力,而react跟vue对于现阶段的前端来说等于各占据了前端领域的半壁江山,对于我来说由于我长时间接触的是vue,对于vue我也是花了很长时间去深入理解底层源码这中间给了我很大的收获,但是react却一直停留在会用但不知原理的程度,这对我来说是一块不足的地方,我希望能够对react有一个全面的学习

②对于自身而言编程即是我的工作也是我的一个兴趣爱好,对于底层原理的探索也是我自身很乐意的一键事情

学习react源码难吗?

老实说确实挺难的,在学习react之前我也是花了3~4个月的时间学习过vue的源码,并且自己也写了一遍vue的阉割版的实现,对于vue有3大核心部分,分别是响应式模块、运行时模块、编译时模块。对于学习完这些的我总是抱着一股对于vue的自信,在公司平常写业务代码的时候也自信无论遇到什么总是能从源码的角度上去分析,能解释出一些现象的原理,而react起初在我看来由于编译时是由babel实现的加上同样都是虚拟dom、diff算法等等跟vue大相径庭的概念,从我对于vue源码的理解,觉得学习react我应该可以比vue更短的时间内学完,然后结果却是到目前为止过去了大约半年的时间我才学完了大部分,我学习是借助于周末的时间以及平常工作日的空闲时间去学习的,当然有时候加班或者是平常有朋友约出去,或者是今天上班的工作太多导致回家的时候已经极度疲劳,也并非每天都是在学习。但可以说在我看来react的源码是要比vue难的,相对于vue感觉react多了很多复杂的概念,印象最让我深刻的是react有两套虚拟dom,而由于先接触vue的我,由于vue只有一个vnode,从一开始就在思考为什么react既要有ReactElement还要有FiberNode,这两套在我看来就是数据结构不同的两套东西来表示,另外一个类似的地方就是优先级Lane也是跟调度器scheduler内部的优先级不是同一套,中间也是实现了一个相互转换的方法,到现在为止给我的感觉更像是这些概念是中间插入进来的,fiberNode像是由于为了兼容旧的东西而不能破坏原有的ReactElement数据结构,但是为了解决性能问题而又必须引入的新的一个数据结构,因此react给我的感觉他比vue要更复杂一些。

如何学习react

我是通过卡颂老师的《从零实现React18》的课程去一步步看着视频学习的,我的编程能力说实话算很普通只能通过这种方式来学习,如果是本身水平比较高的话自然不用像我这种方式,可能自己看看文档就可以了,所以这类人可以忽略我的话

咬紧牙关撑住第一个最大的门槛

视频的课程可以说确实需要一定的毅力才能学的下去,尤其是最开始从0搭建reatc直到实现了第一个调试方式,能跑通项目并且能看到界面的时候这一个过程是最难的,因为这个时间接触到的概念是最多的例如ReactElement FiberNode Update UpdateQueue render阶段(包括beginWork, completeWork) commit阶段(cimmitWork)后续还有hook之类的跟组件相关的暂且不提,但这些概念是组成一个最基本能跑通流程的不可缺少的元素,你不得不一口气接触这么多概念才能够看到一个效果,但是这些概念对于一个刚接触源码的人来说是很奔溃的,一下子要往脑海里塞大量的新的概念,还都是不好理解的东西,而我的做法是撑住跟着视频一步步实现自己的代码,这个过程是非常慢的一点点跟着视频写,并尝试去理解这些东西,有些实在理解不了的可以先写着,暂时跳过理解这个阶段,直到完全实现出能看得到效果的流程,这个时候别继续往下看了,停下后面东西的学习,回过头来再次审视这个阶段的整个代码,重新看一遍代码,想一想是不是每个步骤能理解为什么要这么做,并能完整看懂最终渲染到界面的每一个流程,我在这个阶段花了非常多的时间,不断的使用console.log打印观看中间的数据的转化,我会把我每一步的理解都写上注释在代码中,所以我的源码中充满了注释,感觉是注释比真实的逻辑代码还多,内心已经将他当成自己的笔记了,知道我认为已经掌握得差不多的时候(这个时候上面说的东西也并非完全清楚这个所有的概念,因为因为包含的东西很多,并且后续还有很躲东西需要反复的在这上面去添加的,需要在后续继续学习的时候不断的重复看这些才能真正的掌握好整个react的核心思想)我才会接着下一个视频继续看,继续反复的上一个步骤,看到一个阶段中断视频,调试代码,仔细理解,写注释。

学习过程中的知识分享

卡颂老师的能力比较高,他的课程给我的感觉很相信学生的能力,对于一些知识可能不会做太多的说明,有一些我不懂的时候也是额外花时间去琢磨学习的,下面是分享一些我认为课程中没有提及但可能不是所有人都能理解的地方,对于课程中提及的点就不再做更多的重复性说明了,我认为这意义不大,如果说的不对的地方还请见谅并指出,我也是一个学习分享的心态来说的

我自己实现的react的github地址 github.com/LinJiaHongA...

1.babel到底做了什么工作,负责了什么?

对于react编译时是借助babel完成的,因为react是jsx这种通过js来描述html的语言,但是浏览器原生却并不支持jsx所以需要经过babel来转换,但是babel转换的结果却不是直接生成ReactElement,而是生成了React.createElement(旧版)或jsx等作为函数名的函数调用,并将对于的数据通过参数传入进来,但是本身并没有帮我们实现这两个方法,这两个方法是react模块内实现的,babel是转行为了调用这两个函数的代码,而react负责提供这个方法,这个给我的感觉类似于jsonp。

babel是如何知道jsx中的节点是组件还是一个普通节点

这一点其实可以打开babel的官网在上面的编译调试自己输入一下就知道了,babel看首字母是否是大写,以及是否是通过'.'来取值,分为3种情况

typescript 复制代码
<div>普通节点</div>
<abc>普通节点</abc>
// 第一种普通的element节点由于div或者abc都是小写,所以babel会认为是字符串,
// 这个时候经过createFiberFromElement生成的FiberNode是HostComponent也就是会被认为是普通节点类型
//  jsx('div', { children: ['普通节点'] })
//  jsx('abc', { children: ['普通节点'] })

<Abc>变量节点</Abc>
// 为什么说是变量节点而不说是组件呢,因为后续的Suspense这种由react内部的能力的东西说是组件好像也不是我们认为意义上的组件,因此我成为变量节点,但实际上跟组件是一个原理的,babel本身并不会区分是Suspense还是组件,他只认为这是一个变量,会编译为
// jsx(Abc, { children: ['变量节点'] })
// 至于这个Abc是啥这个需要我们自己实现,只不过Suspense是由react内部实现,而通常我们使用的组件使我们自己定义的函数或者类,由于jsx调用的第一个参数是变量那自然生成的element的type值就是实现这个变量的值

<abc.name>变量节点</abc.name>
// 这个时候由于有了'.'这个东西那么他也会直接认为是变量,不管首字母是否是大写都会认为是变量,最常见的就是<context.Provider value={'a'}>
实际上会编译为jsx(abc.name, { children: ['普通节点'] })就需要有一个叫abc的对象内部有一个属性叫name会那这个name的值作为type

按位操作

源码中经常会见到这类代码

scss 复制代码
(finishedWork.subtreeFlags & MutationMask) !== NoFlags

其中&就是安位与,这个知识其实我是在学习vue的过程中就碰到的,因为通常写业务代码不会用上这个,所以第一次见的时候有点闷逼

其实就是按位操作符,他的具体的操作其实有很多这里只说两个最常见的,按位与'&'跟按位或'|'

他的作用就是一个数字可以起到类似对象的作用表示多钟结果

ini 复制代码
用1来表示true,0来表示false,一个数字的位操作符一般都是0b00000010其中,1在第2个位置方出现表示某一种情况或某一种类型为true,第一个位置为0表示为false  
按位或表示添加某一个情况
const types = 0b00000010
types = types | 0b00000001
这样子得出来的值表示types=0b00000011,表示情况1情况2都是true
有点类似对象一样的能力,通常在对象中我们可能会这么表示 
const types = {type: true, type2: false}
types.type2 = true

按位与表示查询某个值在集合中是否为true
例如查看type2是不是为true
type2结果 = types & type2
假如types = 0b00000011 那么结果是1为true
假如types = 0b00000010 那么结果就是0为false
通常在对象中我们可能会这么表示
type2结果 = types.type2
相关推荐
起这个名字2 分钟前
LangGraphJs 核心概念、工作流程理解及应用
前端·人工智能
小赵同学WoW3 分钟前
vue组件基础知识
前端
牛奶12 分钟前
浏览器藏了这么多神器,你居然不知道?
前端·chrome·api
WebInfra17 分钟前
Rspack 2.0 正式发布!
前端·javascript·前端框架
极速蜗牛24 分钟前
Cursor最近变傻了?
前端
码字小学妹34 分钟前
Claude Opus 4.7 接入指南(2026):国内配置 + xhigh 推理 + 成本计算
前端
小赵同学WoW35 分钟前
插槽【vue2】与 【vue3】对比
前端
代码随想录36 分钟前
Agent大厂面试题汇总:ReAct、Function Calling、MCP、RAG高频问题
前端·react.js·前端框架
前端那点事36 分钟前
Vue响应式原理|从底层实现到面试考点,一文吃透(Vue2+Vue3全解析)
前端·vue.js
walking95738 分钟前
Vite 打包优化终极指南:从 30MB 到 800KB 的性能飞跃
前端·vue.js·vite