---
# System prepended metadata

title: React 筆記
tags: [前端]

---

## React 筆記

### Component-based Design (元件導向)
React 函式庫提供 **Component 類別** 讓工程師以繼承 **(extends)** 此模板方式進行網頁開發，此元件可以重複使用，<font color='blue'>透過 override (覆寫) **生命週期函式** 的界面來執行 UI 互動、網路存取、資料變更...等其他程式流程</font>，資料流為 **單向資料流**，父元件資料可層層傳遞給子元件。

React Component 有兩種方式可以取得資料，(父元件)從外部傳入資料會保存於 **props** 名稱之變數，內部資料保存於 **state** 名稱之變數。

內部僅 **<font color='orange'>render()</font>** 方法為必要，其餘方法非必要。

- **stateful vs stateless**
> 1. **stateful 元件**：內部帶有 state 變數的元件。
> 2. **stateless 元件**：內部不帶有 state 變數的元件。

- **controlled vs uncontrolled**
> 1. **controlled 元件**：資料狀態保存於 **state** 上。
> 2. **uncontrolled 元件**：資料狀態保存於 **DOM 元素** 或是 **refs(RefObject)** 上。

### Life Cycle（生命週期）
主要分為三大週期：**Mounting、Updating、Unmounting**。(下圖為 v16.4 以上)

![image](https://hackmd.io/_uploads/Hkc854A31x.png)


- **Mounting 階段**
當一個 component 的實例(instance) 初次被建立且加入 Virtual DOM 中時，其生命週期將會依照下列的順序呼叫這些方法：

  :::info
  1. <font color='orange'>**constructor()**</font>
     - 初始 state。
     - 綁定函式，如 
       ```javascript!
       this.handleClick = this.handleClick.bind(this);
       ```
     - 若無初始或綁定動作，則可 **不需要** 覆寫建構子。
  3. <font color='orange'>**render()**</font>
  4. <font color='orange'>**componentDidMount()**</font>: 於掛載後僅 **執行一次**。
  :::

- **Updating 階段**
當 props 或 state 有變化 或 強制更新 時，就會 **觸發更新階段**。當一個 component 被重新 render 時，其生命週期將會依照下列的順序呼叫這些方法：

  :::info
  1. **static** getDerivedStateFromProps(**nextProps**, prevState)
     - 此為 **類別函式**，掛載與更新兩個階段皆會被執行。
     - 當 props 變動、setState() 或是 forceUpdate() 就會被觸發。**(>=v16.4)**
       只有 props 變動才會被觸發。**(v16.3以下)**
     - 回傳 null 時表示不更新 state，若回傳一個物件則更新 state。
     - 可取代即將廢棄 **componentWillReceiveProps()**。
  3. <font color='blue'>**shouldComponentUpdate()**</font>
  4. <font color='orange'>**render()**</font>
  5. getSnapshotBeforeUpdate(prevProps, prevState)
     - 可以透過傳入參數訪問 DOM 更新前的 **props 與 state**，作為快照傳給 componentDidUpdate()。
     - 回傳值可當作參數傳給下一個函式 componentDidUpdate() 的第三個參數。
     - <font color='red'>注意! 必定要與 **componentDidUpdate()** 搭配一起使用，否則編譯時會報錯!(有 4，則 5 一定要覆寫)</font>
  7. <font color='orange'>**componentDidUpdate(prevProps, prevState, snapshot)**</font>
  :::


- **Unmounting 階段**
當一個 component 從 Virtual DOM 中被移除時，這個方法將會被呼叫：
  :::info
  1. <font color='orange'>**componentWillUnmount()**</font>
  用於 **註銷或解除** 元件銷毀後將不再使用的事件或資源。
  :::



### Virtual DOM
Virtual DOM 是通過 JavaScript 物件儲存在記憶體中，模擬真實 DOM 的方法。不只是 React，其他框架（Vue）也有 Virtual DOM 的應用。

:::success

:bulb: Virtual DOM is a **lightweight copy and virtual representation** of the actual DOM. It is also <font color='orange'>**an abstraction**</font> of the HTML DOM. 

:::

#### DOM Diff
當 DOM 的節點需要更動時，不會直接修改 DOM，而是透過 DOM diff 演算法 **比較 Virtual DOM** 修改前與修改後的樹狀結構，再批次更新真實的 DOM 節點。

![image](https://hackmd.io/_uploads/BkK-RpSfC.png)


#### 解決效能問題
直接操作 DOM 雖然快速、方便，但是瀏覽器所耗費的成本極大，故 <font color='orange'>**在頻繁操作 DOM**</font> 的情境下則會導致瀏覽器效能低下甚至畫面卡頓，因此透過 Virtual DOM 可優化效能。
（不會只因為<font color='red'>**連續改一個小節點**</font>，而一直遍歷整個 Tree，造成效能低下）

### 參數傳遞
- **父元件向子元件傳遞**
透過 props 參數傳遞，遵循『單向資料流』方向，不能反向傳遞。
  :::success
  :bulb: **Props Drilling**
  多層嵌套的元件，則會發生 **Props Drilling 問題**，即 <font color="red">中間組件必定會被**傳遞參數**探鑽</font>，造成元件不易維護的問題
  :::

- **子元件向父元件傳遞**
子元件可以透過 **callback 回調函式** 向父元件傳遞子元件的內部資料。

- **向其他元件傳遞**
  -  React 本身提供 **Context API 來分享狀態**，亦可提供局部共享範圍(可包在大型、複雜的組件下限定共享範圍)，可與第三方管理工具靈活搭配。
  - 第三方狀態管理工具，常見有：Redux、MobX、DvaJS ... 等。

    :::success

    :bulb: DvaJS 是一套基於 **Redux 與 Redux-saga 的資料流解決方案**，為了簡化開發流程，亦內建 react-router 與 fetch，可視為一個輕量級的框架了。

    **DvaJS 框架**
    ![image](https://hackmd.io/_uploads/HkJo3ZwMC.png)

    :::

### 參考網址
1. [React.Component](https://zh-hant.legacy.reactjs.org/docs/react-component.html)
2. [請解釋 React 生命週期？]( https://www.explainthis.io/zh-hant/swe/react-lifecycle)
3. [什麼是 Virtual DOM?](https://www.explainthis.io/zh-hant/swe/react-virtual-dom)
4. [Virtual DOM & DOM Diff]( https://tutorialslink.com/Articles/What-is-Virtual-DOM/1580)
5. [React 生命週期圖示](https://projects.wojtekmaj.pl/react-lifecycle-methods-diagram/) 

