## **如何閱讀大型開源專案的程式碼**
1. 不要為了看程式碼而看程式碼
1. 解決遇到的問題
2. 想了解整個 React 系統結構的想法 & 實踐過程🤔
2. 前置了解 → 本文分享內容🥹
1. 這個專案中可以分成幾個部分
2. 之前的交互關係是什麼
3. clone → local build
https://github.com/facebook/react
React 中有個方便測試的檔案 dev.htm 可以快速查看我們在 local 端的變動
> The easiest way to try your changes is to run yarn build core,dom –type=UMD and then open fixtures/packaging/babel-standalone/dev.html. This file already uses React.development.js from the build folder so it will pick up your changes.
>
>
> **[Development Workflow](https://legacy.reactjs.org/docs/how-to-contribute.html#development-workflow) - React official website**
>
4. 了解目錄結構
5. 善用 debugger & 全局搜索
6. 關注專案 & 核心開發者
1. [React blog](https://react.dev/blog)
2. [**Dan Abramov](https://twitter.com/dan_abramov)** → 已離開 meta
3. [Andrew Clark](https://twitter.com/acdlite)
4. [Sebastian Markbåge](https://twitter.com/sebmarkbage)
## Core
:::info
🚧 **架構概覽圖**

:::
:::spoiler 🧑💻 從 user 的角度去理解 React 的核心運作
1. **User Interaction**
使用者點擊按鈕觸發點擊事件。
2. **Event Handling**
React DOM 捕獲並處理點擊事件,呼叫 **`handleClick`** 函式。
3. **React Reconciler**
**`handleClick`** 使用 **`setCount`** 更新狀態,啟動 **`react-reconciler`**。
4. **Scheduler ➡️** 更新過程的起點
**`scheduler`** 安排一個更新任務。
5. **Re-render**
**`react-reconciler`** 比較虛擬 DOM,生成新的 Virtual DOM。 → Diff
6. **React DOM**
**`react-dom`** 使用新的虛擬 DOM 操作實際 DOM。
7. **Browser Rendering**
瀏覽器接收到對 DOM 的變更,執行重新排版(Reflow)和重繪(Repaint)。
:::
### Scheduler
為 React v16 之後新增的機制(React fiber)
> **安排**一個更新的**任務**,確保 React 的整體性能和用戶體驗。
>
- **避免阻塞**瀏覽器的主線程(避免畫面卡頓or白屏)
- 大任務分隔成多個小任務(chunks)
- 將小任務分到多個時間片段(time slice)執行 → 通常對應瀏覽器的一幀(Frame)
- **資源利用**
- 盡可能利用空閒時間執行任務,最佳化系統資源。
- 🎈**調度優先的任務**優先進入 `Reconciler` 執行(藉由 `Reconciler` 提供的 `callback function`)
- 中斷和恢復機制
- → 維護一個任務 queue
→ [work loop] 循環直至清空 queue
[](https://github.com/facebook/react/blob/1fb18e22ae66fdb1dc127347e169e73948778e5a/packages/scheduler/README.md)
⬆️ 是獨立於 react 的 experimental package
- **Appendix**
Scheduler 的概念其實已經有部分瀏覽器實踐出來了 → **[requestIdleCallback](https://developer.mozilla.org/zh-CN/docs/Web/API/Window/requestIdleCallback)**
但基於以下考量 React 團隊放棄使用 選擇自己創建🧐
- 跨瀏覽器一致性
- 更好的配搭 React Fiber 架構
- 有更高的優先級
- 更精細的任務控制(time slice)
- 可根據不同場景進行優化
### Reconciler
> 負責處理與協調 Virtual DOM 與 Real DOM 的同步。
>
[](https://github.com/facebook/react/blob/v17.0.2/packages/react-reconciler/README.md#practical-examples)
⬆️ 也是獨立於 react 的 experimental package
- Virtual DOM 的生成、比較和更新過程(包含 `Diff` 算法)
- [work loop] 建構 `fiber樹`
- 使用不同的 Reconciler 以實踐不同的環境
- React DOM Reconciler → ****Web
- **React Native Reconciler** → mobile
- **React Three Fiber Reconciler** → web with 3D(three.js)
- **React VR Reconciler** → VR
最終 React-Reconciler 會將 Virtual DOM 變動的部分做上記號([如下](https://github.com/facebook/react/blob/1fb18e22ae66fdb1dc127347e169e73948778e5a/packages/react-reconciler/src/ReactSideEffectTags.js))交給 Renderer(react-dom 接口) 🙌
```jsx
export const Placement = /* */ 0b0000000000010;
export const Update = /* */ 0b0000000000100;
export const PlacementAndUpdate = /* */ 0b0000000000110;
export const Deletion = /* */ 0b0000000001000;
```
### R**eact DOM**
> 根據 Reconciler 為 Virtual DOM打的標記,同步執行對應的 DOM 操作。
>
## APIs
### ReactElement
#### createElement
```jsx
// createElement 這個 function 接收 **type**, **config**, **children** 三個參數
export function createElement(**type**, **config**, **children**){}
```
除了 div 之外,react-component 也是 type 的一種。
- **config**
```jsx
if (config != null) {
if (hasValidRef(config)) { // ①:ref
ref = config.ref;
if (__DEV__) {
warnIfStringRefCannotBeAutoConverted(config);
}
}
if (hasValidKey(config)) { // ②:key
if (__DEV__) {
checkKeyStringCoercion(config.key);
}
key = '' + config.key; // string
}
// ③:babel 轉換的屬性
self = config.__self === undefined ? null : config.__self;
source = config.__source === undefined ? null : config.__source;
// ④:Remaining properties are added to a new props object
for (propName in config) {
if (
hasOwnProperty.call(config, propName) &&
!RESERVED_PROPS.hasOwnProperty(propName)
) {
props[propName] = config[propName];
}
}
}
```
1. **handle `ref` and `key`**
2. **handle `__self` and `__source` covert by babel**
使用 Babel 或其他 JSX 轉譯器來轉換 JSX 語法為 JavaScript 時,這些轉換器有時會在轉換過程中添加額外的屬性到 React 元素上,以**提供開發者更多的調試**和**錯誤追蹤的資訊**。
- __self:用於追蹤 React 元素被建立時的 **`this`** 指向
- __source:包含元素在原始程式碼中的位置信息
- JSX → JS code(by Babel)
```jsx
import React from 'react';
const MyComponent = () => {
return React.createElement("div", {
__self: this,
__source: {
fileName: _jsxFileName,
lineNumber: 6,
columnNumber: 12
}
}, "Hello, React!");
};
export default MyComponent;
```
```jsx
import React from 'react';
const MyComponent = () => {
return React.createElement("div", {
__self: this, // -> App
__source: {
fileName: _jsxFileName, // -> path/to/MyComponent.js
lineNumber: 6,
columnNumber: 12
}
}, "Hello, React!");
};
export default MyComponent;
```
- **children**
```jsx
// Children can be more than one argument, and those are transferred onto
// the newly allocated props object.
const childrenLength = arguments.length - 2; // ①:處理第三個 arg and 之後的
if (childrenLength === 1) { // ②: 1 個 child 會是 object
props.children = children;
} else if (childrenLength > 1) { // ③:大於 1 個 child 會是 array
const childArray = Array(childrenLength);
for (let i = 0; i < childrenLength; i++) {
childArray[i] = arguments[i + 2];
}
if (__DEV__) { // 凍結 object 防止之後的處理被修改
if (Object.freeze) {
Object.freeze(childArray);
}
}
props.children = childArray;
}
```
- return **reactElement**
```jsx
return ReactElement(
type,
key,
ref,
self,
source,
ReactCurrentOwner.current,
props,
);
```

- 調度優先的任務**優先**進入 `Reconciler` 執行
- 中斷和恢復機制