# react-on-the-way
**Repository Path**: yse/react-on-the-way
## Basic Information
- **Project Name**: react-on-the-way
- **Description**: No description available
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2020-09-11
- **Last Updated**: 2020-12-19
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README

# React-On-The-Way
基于React`V16.13.1`架构,从零实现React 🎉🎉🎉
# 配套教程
React技术揭秘
👋👋👋 文章有任何不清楚的地方,欢迎给我提PR
## 为什么会有这个仓库?
我假设React是你日常开发的框架,在日复一日的开发中,你萌生了学习React源码的念头,在网上搜各种源码解析后,你发现这些教程可以分为2类:
1. 《xx行代码带你实现迷你React》,《xx行代码实现React hook》这样短小精干的文章。如果你只是想花一点点时间了解下React的工作原理,我向你推荐 这篇文章,非常精彩。同时,这个仓库可能不适合你,因为他会花掉你很多时间。
2. 《React Fiber原理》,《React expirationTime原理》这样摘录React源码讲解的文章。如果你想学习React源码,当你都不知道`Fiber`是什么,不知道`expirationTime`对于React的意义时,这样的文章会给人“你讲解的代码我看懂了,但这些代码的作用是什么”的感觉。
这个仓库的存在就是为了解决这个问题。
简单来说,这个仓库有对应的一系列文章,文章会讲解React为什么要这么做,以及大体怎么做,但不会有大段的代码告诉你怎么做。
当你看完文章知道我们要做什么后,再来看仓库中具体的代码实现。
同时为了防止堆砌过多功能后,代码量太大影响你理解某个功能的实现,我为每个功能的实现打上一个`git tag`。
## 历史版本预览
通过切换`git tag`浏览不同完成度的项目,执行`npm start`启动该版本下的Demo
### 当前版本v6
v6 diff v5
v6实现了React的异步调度器Scheduler(也就是说我们实现了`requestIdleCallback` polyfill),并使用`Scheduler`实现了异步render,也就是React ConcurrentMode。
之前的版本中,我们都是同步执行render流程。在v6中,我们会为产生的`update`赋予一个优先级,高优先级的`update`会优先进入render流程。甚至当低优先级的`update`在render过程中我们触发了高优先级`update`,这时会搁置低优先级render转而处理高优先级render,这很酷,不是么😄
相对应的,v6相对v5增加了大量代码和一些全局变量。不过没关系,我会在之后的文章介绍这一切是如何做到的。新增功能如下:
1. Scheduler模块
2. fiber的优先级冒泡机制
3. ConcurrentMode
这真是React内部最复杂的机制了,让人头秃👨🦲
### v5
v5 diff v4
在v3中我们实现了状态更新,直接在`FunctionComponent`函数体内触发更新会造成死循环,所以我们用计时器来触发。在业务中,我们一般是通过:
1. 回调函数(ex:onClick)
2. `useEffect hook`
3. `ClassComponent`生命周期钩子
来触发。既然我们已经实现了`useState hook`,这一版我们就实现`useEffect hook`,新增功能如下:
- [x] `useEffect hook`首屏及再次渲染的完整逻辑
### v4
v4 diff v3
之前只能更新单一节点,这次实现了大名鼎鼎的React Diff算法,可以更新多个兄弟子节点了😄,新增功能如下:
- [x] 节点支持`key`prop
- [x] `commit`流程支持`Deletion effectTag`处理
- [x] `reconcileChildrenArray`支持非首次渲染的diff算法
ps:支持`Deletion effectTag`处理是为了应对:
```javascript
// 首屏渲染的组件
[a, b, c]
// 再次渲染的组件
[a, null, c]
```
在这种情况下b fiber被标记为`Deletion effectTag`,对应的DOM节点需要删除
### v3
v3 diff v2
之前的版本只实现了首屏渲染的逻辑,即使在v2中实现了`useState`也只实现了`useState(initialValue)`带来的首屏渲染,在v3中我们终于实现状态更新啦,撒花🎉,新增功能如下:
- [x] `useState hook`对单一`HostComponent`的状态更新
ps:之所以只支持单一`HostComponent`,是因为还没有实现`key`以及`diff`算法,所以无法支持多个兄弟组件的更新
🐛当一个组件中使用多个`useState hook`且他们的更新函数同时触发,如示例中:
```javascript
// 会造成页面逐渐卡顿并最终崩溃的例子
function App({name}) {
const [even, updateEven] = useState(0);
const [odd, updateOdd] = useState(1);
setTimeout(() => {
updateEven(even + 2);
updateOdd(odd + 2);
}, 2000);
return (
)
}
```
react-on-the-way会造成页面逐渐卡顿并最终崩溃。原因是`updateEven`和`updateOdd`方法会分别开始一次新的更新流程。
在其中每次更新流程执行到`updateFunctionComponent`时会调用`App`函数,在函数内部会调用计时器并在2000ms后又调用这2个更新函数,从而又开启新的更新流程。更新流程的数量会指数增加并最终崩溃。
造成这个问题的原因是我们还没有实现React的任务优先级机制与任务的批处理。在React中,
- 同步模式下同一个事件函数内的同步更新会被批处理,只产生一次更新流程
- 异步模式下所有更新都会经过优先级调度
### v2
v2 diff v1
为了实现React的页面更新逻辑,需要改变状态(state),我们有2条路可选:
1. 实现`ClassComopnent setState`
2. 实现`FunctionComopnent useState`
考虑`hook`是React的趋势,我们优先实现`useState`,所以v2我们在第一版基础上增加了`FunctionComponent`相关首屏渲染,新增功能如下:
- [x] `FunctionComponent`类型组件的首屏渲染
- [x] `hook`架构体系
- [x] `useState hook`首屏渲染做的工作
### v1
我们的首要目标是实现React的页面更新逻辑,基于这个目标,我们首先实现了`HostComponent`的首屏渲染,新增功能如下:
- [x] Render-Commit整体架构体系
- [x] `HostComponent`的首屏渲染
🙋♂️小讲堂:`HostComponent`是指原生DOM组件对应的JSX,在React执行时产生的组件
```jsx
// 比如这样
Hello
```