---
# System prepended metadata

title: 《React 思維進化》第三組讀書會小組討論筆記
tags: [React 思維進化]

---

[TOC]

# 2024/3/17 2-6 ~ 2-7

簡報: https://hackmd.io/@pinkymini/S1tYH5bTa#/

導讀人： 粉粉
筆記工： Vera

## 2-6
#### 單向資料流
- 資料傳遞單向不可逆向
![image](https://hackmd.io/_uploads/BJbJ2-ERa.png)
- 資料驅動畫面：不會在原始資料更新以外的情況下更新畫面
- 資料與畫面分離管理：更好實踐資料驅動畫面

#### 單向資料流常見應用
- 資料傳遞方向：資料從父層向下傳遞
- 更新資料方向：需透過事件去從父層更動資料，不能從子層更動

#### 資料 -> DOM 實際渲染的策略：
- 資料更新後，人工判斷並手動修改對應 DOM element
    - 可以只更新需要更新的部分來節省效能
    - 需要人工判斷並維持單向資料流，難度高
- 資料更新後，整個 DOM 全部清除，以最新的原始資料重繪
    - 直覺
    - 效能問題：大量操作不需要被操作的 DOM

#### 前端框架中的應用
- 結合 Virtual DOM
- 前端框架都是選擇單向資料流
    - React 策略二
    - Vue 策略一
- 雙向資料流之說
    - Vue: V Model，實際上是雙向綁定「語法糖」
- 選擇原因
    - 限縮變因：可維護性、可讀性，減少資料意外出錯、可進行有效的效能優化

#### 雙向綁定
- 資料同步到畫面，畫面也可能同步到資料
    - 唯一例外（畫面到資料）：input 本身是自帶狀態，執行由瀏覽器維護、儲存。input 觸動 `onChange` 事件，瀏覽器可以直接蓋回資料，不需要人工處理。相對而言，單向資料流：e.g. React 需要使用 `setState` 去更動資料。


## 2-7
#### component
- 開發者自定義的畫面元件藍圖，可以重複使用，內涵特定畫面意義與邏輯
- 抽象化：定義 component 時，會將邏輯與實際用途明確地定義出來

#### component 定義＆呼叫
- 透過 JS 函式定義，把 props 傳入，回傳 React element
- compononent function 第一個字母須大寫：JSX 會根據命名來判斷 DOM element 或 Component function
- 呼叫：
```javascript=
// 透過建立 React comoponent 形式被呼叫
const reactElement = <CustomButtom />
// 轉譯成以下
const reactElement = React.createElement(CustomButtom)
```

- component vs. React element
    - component 是 React element 的藍圖，可以比喻成食譜
    - React element: 建構畫面的最小單位，是實際產生的結果，可以比喻成菜餚

#### props
- 客製 component 的屬性，被當作參數傳遞的 props 會被打包成一個物件，讓 component 依照不同情境產出符合需求的 React element
- 使用：
    - 透過 props 取得自定義 props 物件：e.g. `props.price`
    - 解構
    - 特殊 props: `children`
- props 是**唯讀**而不可修改
    - 維護單向資料流的可靠性：開發環境下的 React 會把 props 物件先以`Object.freeze(props)` 做處理，避免不小心改動到。如果指向到同一個記憶體位置，即使值不同，`Object.freeze()` 也不會起作用

#### 父 component 與子 component
- component 裡面呼叫另一個 component 來組裝畫面

#### component 的 render 和 re-render
- render: 首次呼叫 component function
- re-render： 狀態資料更新，再次呼叫 component function
- render 從上到下，由外至內。當父層 component render 即使子層沒有變更，底下子層也會 render

## Q & A
#### Q: 當第一個H2Component有狀態的更新時，會發生什麼事？
![image](https://hackmd.io/_uploads/BJymPzVAp.png)
A: 呼叫第一個 H2Component 的 component function，依序呼叫裡面的 PComponent 進行 render。不會影響到第二個 H2Component，因為只有第一個 H2Component 的狀態更新。 


#### Q: 試著講出一個內含子component的父component在資料更新後，會發生哪些事情？
A: 父 component 更新，會觸發子 component 的 re-render


#### Q: 滾動時畫面為什麼那麼卡？

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

A: 父層 position 一直被更改，因此子層會不斷 re-render。

解法：
將不能更動的子層 components 包成 slowComponent。在新舊比對中，因為原本的版本因為每次創建都是新的 object，記憶體位址也不相同，所以會需要不斷改動，但以下方解法在比對中是相同的，就可以避免多餘的 re-render。
![image](https://hackmd.io/_uploads/Byx_9zV0a.png)

#### Q: 雙向資料流在 React 上的實作
A: React 本身沒有雙向資料流，也做不到。該情境會使用 state 管理資料，將 state 設定在 input 上，觸動事件去觸發 setState 做更改，i.e. 單向資料流的設計需要開發者自己去處理這段。

#### Q: P.141 筆者思維分享與高內聚低耦合之間的 trade-off 設計？
A: （component 設計心法，Zet 的經驗，是沒有特定解答的。如果要認真回答可以寫一本書。）

設計不能只是單純處理眼前情境，需要思考抽象意義分層，e.g. 兩個長得很像但實際不一樣的功能，就不能設計在一起，A、B props 都不重複
=> 拆解分層、抽出共同部分。可以拆很多層，不同層都有它特定的意義，避免拆很多卻不能定義清楚它的意義。從意義去思考，而不是單純讓它動起來。
1. 假設 A、B 都有商品列表，商品列表就可以抽出來
2. 假設只有 UI 重複就只把 UI 抽出來，不同部分用 props 傳入。

-> Q: 這是讓元件變成 presentation component 和 container Component 嗎？

A: 這只是部分概念。開發者也可以每一層都有資料邏輯，不過每一層都有它的意義範圍。

-> Q: 考慮 MVC 方式去拆分component 嗎？
A: 前端不太用 MVC，component 不是用 MVC，component 主要是增加獨立性、降低耦合性，有他自己的邏輯、樣式模板。

## 補充
#### 補充 1
![image](https://hackmd.io/_uploads/SkSoAM4C6.png)
P.115 React element 類型非 component 實例。
component 實例才擁有自己的狀態

#### 補充 2
[Discord 相關問題參考](https://discord.com/channels/1174010592282034216/1216737172162609283/1216737172162609283)
- 為什麼使用 `React.createElement()`？
- 什麼時機點會執行 component？

1. `<App />` 與 `App()` 的差異
    1.1 是否會被立刻執行？是否會被當成 component 實例？

    ```javascript!
    // 不會
    const a = <App />;
    console.log(a);

    // 一般 function call 方式，會立刻執行，但不會被當作一個 component，不會去建立 component 實例
    const b = App();
    console.log(b);
    ```
    1.2 React 以是否透過 `React.createElement()` 呼叫 來判斷是否是 component，而不是透過 function name 是否開頭為大小寫。透過 function call 的方式不會產生 component 實例（可使用 React dev tool 去證實）

    ```javascript
    export default function App() {
      return (
        <div className="App">
          App
          <Foo a={10} />
          {Foo()} // 不會被看作是 component
        </div>
      );
    }
    ```


2. 延遲執行：執行完 `React.createElement()`，但還 `<Foo/>` 沒有實際被 call 到

- 好處：可以在內容沒有被更動時，不去 re-render。

- 到 line 14 還沒執行 `<Foo/>`，component return 後會去 reconciler 觀察是否轉換成 DOM element，之後才會交給 renderer 去處理 DOM element。

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

    - React element 是不同歷史時刻的樣子。fiber node 才是最新狀態，需要時才會同步到 DOM element

- 可參考 P.134 範例。React element 被 return 後才會執行 P.136 的流程。
- 如果物件不變，會跳過 `<Foo/>`，直接沿用上一次的結果。
- props 不固定的情況：可以使用 component 類型的 React element，讓延遲執行下的比對，記憶體位置是一樣的，就會會去沿用上一次的內容。


3. Zet 提醒用簡單的例子去實踐、理解，這個步驟很重要的習慣！！會幫助理解與內化。


# 2024/3/31 2-8 ~ 2-9

簡報: https://hackmd.io/@pinkymini/S1tYH5bTa#/

導讀人： Nono Lin
筆記工： 粉粉


## 2-8
#### state