## CH.4 Component 的
## 生命週期與資料流
#### 《React 思維進化》
2024/5/15 導讀人:LJBL
Note: spotlight 效果要打開右上角的分享 > 自訂簡報選項,輸入:
spotlight:
enabled: true
---
## 4-1 Component 的生命週期
| 名詞 | 定義
| ---- | -----
| component | 以函示定義與封裝的 <span>藍圖<!-- .element: class="fragment" style="color: #1b22f5" data-fragment-index="1"--></span>,內含所希望的內容、行為、特徵與流程。
| <span>實例<!-- .element: class="fragment" style="color: #1bf58f" data-fragment-index="3"--></span>|<span>藍圖<!-- .element: class="fragment" style="color: #1b22f5" data-fragment-index="1"--></span>可產生<span>實例<!-- .element: class="fragment" style="color: #1bf58f" data-fragment-index="3"--></span>,每個<span>實例<!-- .element: class="fragment" style="color: #1bf58f" data-fragment-index="3"--></span>獨立存在,互不影響.
| 生命週期 |代表的是一個 <span>component 實例<!-- .element: class="fragment" style="color: #fc499a" data-fragment-index="4"--></span>從出現到消失一個完整的過程。
Note: [hint]先講畫面
交互作用:
component 要怎麼產生實例?就是在呼叫該 cp 時,React 會產生一個獨立的實例,進而出現在畫面上。而從出現到瀏覽器畫面到消失的過程就是該 component 實例的生命週期。
說著很抽象,但生命週期顧名思義,本來就等同生物從從受精卵開始、出生到世界上、到最後生命終結邁向死亡,這裡只是借來使用、主詞換成 component 實例,我們的世界換成瀏覽器而已。
----
### 4-1-1 Component 的三大生命週期
<ol>
<li>Mount<!-- .element: class="fragment" data-fragment-index="1" --> </li>
<li>Update<!-- .element: class="fragment" data-fragment-index="2" --></li>
<li>Unmount<!-- .element: class="fragment" data-fragment-index="3" --></li>
</ol>
<font size=5>※ 無論是 class component 或 function component 都存在<!-- .element: class="fragment" data-fragment-index="4" --></font>
<!-- .element: class="fragment" data-fragment-index="5" -->
Note: 無論你是哪種 cp ,這三大生命週期都是存在的。
透過這章節、幫助我打通一些朦朧的觀念。對於從 class component 就開始學 React 的人來說,這三個生命週期是本來就存在的東西,因此轉變到 fn cp 搭配 hook 的時代,suppose 也是該存在。
但對我這種從 fn cp 往回學的人來說,過去看到 life cycle, mount, unmount 的文章總是自動略過,到了面試的時候,聽到考官一句:『請你解釋什麼是 component 的生命週期?』恍恍惚惚、答非所問。就像葬送的芙莉蓮裡面的弟子費倫、聽到芙莉蓮說『費倫啊~你是不是都沒有讀我給的魔法史書籍~』我跟費倫一樣心虛、或是有看沒有懂。所以今天就是那個直球面對假想大魔王的時刻,也是我選這一章節來報告的契機。
----
## coding time
先來看看熟悉的[那張圖](https://codesandbox.io/p/sandbox/4-1-1-life-cycle-example-ftsngf?file=%2Fsrc%2FApp.jsx)
Note: [demo]兩個按鈕 > 增加圖片 > 刪除圖片
----
## <font class=rainbow-text>那份花了5h+的流程圖</font>
<font size=6>大綱:帶過三個週期/含圖2-9-2</font>
<font size=6>結果:[成果在此](https://www.figma.com/board/JcwpPwbCHjI86HrfySVp3N/life-cycle-of-function-component?node-id=0%3A1&t=NCmgdOLSy7lCQ9Kz-1)</font>
<style>
.rainbow-text {
background: linear-gradient(to left, indigo, purple, blue, dodgerblue, green, orange, red);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
}
</style>
----
剛剛是大家相對熟悉的 function component,那 class component 呢?
----
### Class Component 的生命週期 API -1

<font size=5>derive v. 衍生的</font> / <font size=4>W3C school: [React Class Components](https://https://www.w3schools.com/react/react_class.asp)</font>
Note: 望文生義,一個個帶過。
----
### Class Component 的生命週期 API -2

<font size=5>React 16.3 之後,圖片來源: [Wojciech Maj](https://github.com/wojtekmaj)</font>
Note: 把抽象的東西講具體,用圖是最好的。
----
## 4-1-2 Function Component
## <font color=red>沒有<!-- .element: class="fragment" data-fragment-index="1" --></font>提供生命週期 API
<span>在這個 moment,只要知道沒有就好了<!-- .element: class="fragment" data-fragment-index="2" --></span><span>(??)<!-- .element: class="fragment" data-fragment-index="3" style="color: #fcec03"--></span>
<span>而最常被誤會的 useEffect hook <!-- .element: class="fragment" data-fragment-index="4" --></span><span>並不是 function component 所提供的生命週期 API <!-- .element: class="fragment" data-fragment-index="4" --></span><span>(??)<!-- .element: class="fragment" data-fragment-index="5" style="color: #fcec03"--></span>
----
## 心中充滿<font color=#fcec03>??</font>
<span>好吧,等等~~會劇透~~。<!-- .element: class="fragment" data-fragment-index="1" --></span>
<span>怕暴雷的可以~~左轉先離開~~。(喂!)<!-- .element: class="fragment" data-fragment-index="4" --></span>
Note: 在這個 moment,只要知道沒有就好了,而最常被誤會的 useEffect hook 也並不是 function component 所提供的生命週期 API 。
給 hint 圖 (那篇官方文章三個 method 總和)
----
#### 4-1 觀念檢測
1. 解釋 component 中的三大生命週期運作流程<!-- .element: class="fragment" data-fragment-index="1" -->
2. Function component 有生命週期的 API 嗎?<!-- .element: class="fragment" data-fragment-index="2" -->
Note:
---
## 4-2 Function component 與 class component 的關鍵區別
1. 資料流存取的差異: <font color=yellow>`this` 的行為</font>
2. Function component 的特性:<font color=yellow>自動「捕捉」當下的資料</font>
Note:
我們會先從 資料流存取的差異 開始說起,再帶到 function component 的關鍵特性、造成他們之間的關鍵區別
----
## 4-2-1 this 的存取陷阱
keyword: #非同步 #this.props #mutate #classComponent
----
# `this` 觀念複習
1. this 管的是 ‘before the dot’ 的主體 i.e. Object
2. 直到物件的方法被呼叫之前,this 是沒有值的 i.e. 在 run-time 才被賦值
3. 箭頭函式沒有自己的 this,會向外找到 Object 主體,再沒有就找向 window。
> 好文一生推 [Object method,this`](https://javascript.info/object-methods)
----
# 先說說 class component
書中精彩程式碼[範例](https://codesandbox.io/p/sandbox/4-2-1-function-class-n9g7q6?file=%2Fsrc%2FApp.jsx%3A29%2C9-30%2C32)解說
Note:
[Demo 流程 hints]
- Class component 直接在內部命名函式(OOP 概念、都是該class 的方法)
- 說明 this 指向的地方(找到該主體,也就是該 component)
[最後要 提供解法]
- handleClick 這個內部函式 (inner) 被建立時,它記住了它所屬的外部作用域(lexical env)中的變數,即 showSuccessAlert 和 this.props 裡的 productName ,隨時可調用。
- 閉包(Closure):是函式以及該函式被宣告時所在的作用域環境(lexical environment)的組合。有內部函式跟外部函式。
----
# "class" component
- class 本質上讓 JavaScript 更加地向物件導向 (OOP) 設計靠攏
- 當資料狀態 (state) 改變時,直接以類別 (class) 中的方法(showAlert) 來 mutate 實例的屬性資料 (props) 就是 OOP 一貫做法
```
this.props
this.state
```
- 與 immutable 核心概念的 React 格格不入
----
## <font color=#f91a52>`this`</font> is mutable,
## therefore, it is unreliable.
(in React)<!-- .element: class="fragment" data-fragment-index="1" -->
Note:
----
# 那我說 function component 呢?
書中精彩程式碼[範例](https://codesandbox.io/p/sandbox/4-2-1-function-class-n9g7q6?file=%2Fsrc%2FApp.jsx%3A29%2C9-30%2C32)解說
Note:
[Demo 流程 hints]
帶一下 App.jsx
一樣是傳進 selectedProduct 作為 productName 這個 props 的值,
但是因為 fn cp 在執行的當下、就會創建一個實例,這個實例作用類似快照功能,具體白話地說,就是將當下的 props, state 等資料拍成一張照片留存。
而這裡的 eH 一樣因為 closure 的特性,向該所在作用域找到的 callback fn 及其資料綁定,因而成為該次 render 獨有的 event Handler。這裡就小小劇透到下一個小節。
----
### 關鍵區別
## function component 會自動「捕捉」該次 render 版本的原始資料
- function component 預設幫忙處理<!-- .element: class="fragment" data-fragment-index="1" -->
- class component 需要費心留意 `this` 、有意識地提取脫鉤。<!-- .element: class="fragment" data-fragment-index="2" -->
- this 的本質與 React immutable data 核心相斥<!-- .element: class="fragment" data-fragment-index="3" -->
Note:
1. Function component 很自然地幫我們做好這些事情。該次 render 版本的原始資料都被「捕捉」下來,妥善保存。
2. 而不像 class component 需要費心留意 `this` 、有意識地提取脫鉤。
3. 若從根本上 this 的本質就跟 React immutable data 這個核心相斥,就該思考更適合的設計。
----
# 因此...在 hooks 誕生之後
React 16.8 hooks 的問世,搭配 function component 的組合逐漸取代 class component、且成為 React 團隊強力推薦的主流選擇。
Note:
而也是因為兩者的關鍵區別,導致有了 hooks 的 function component 如虎添翼、逐漸取代 class component、且成為 React 團隊強力推薦的主流選擇。
----
#### 4-2 觀念檢測
1. 在 class component 中的非同步事件裡以 `this.props` 來存取 props 的潛在問題? <!-- .element: class="fragment" data-fragment-index="1" -->
2. 「function component 會自動捕捉該次 render 時的 props 與 state 資料」是什麼意思?<!-- .element: class="fragment" data-fragment-index="2" -->
Note: 自己寫個答案在這裡
---
### (optional)
## 回到 4-1-2 Function Component 沒有提供生命週期 API
(spoiler alert) Ch. 5-2
----
class & fn cp 的範例對比
<font size=5>有一個 FriendStatus component,負責顯示朋友是否在線上。</font>
|  <br> <font size=5>透過 `this.prop` 在<br>(UN)MOUNT 時(取消)訂閱</font> | 
| -------- | -------- |
Note:
帶著解釋一下程式碼
舊的官方 react.org 內容:有一個叫做 FriendStatus component 的範例,這個 component 顯示朋友是否在線上。
#1 我們的 class 從 this.props 中抓取 friend.id,在 component mount 後訂閱好友狀態,
#2 並在 unmount 期間取消訂閱:
但是如果 component 顯示在螢幕上時,從 ChatAPI 來的friend prop 發生變化(也就是資料改變了、被 mutate),會發生什麼事?
FriendStatus component 將繼續顯示不應該存在的好友的上線狀態。這是一個 bug。Unmount 時,由於取消訂閱的呼叫會使用錯誤的朋友 ID,因此也會導致 memory leak 或 crash。
React 官方文件 https://zh-hant.legacy.reactjs.org/docs/hooks-effect.html#explanation-why-effects-run-on-each-update
----
useEffect 對照 React class 生命週期 API
|  |  |
| -------- | -------- |
Note: 在 class component 中,我們需要加入 componentDidUpdate 來處理這種情況:
忘記正確處理 componentDidUpdate 是 React 應用程式中常見的 bug 來源。
----
## useEffect
function component 版本:改搭配 useEffect Hook

它沒有受這個 bug 的困擾。
(但我們也沒有對它進行任何更改。)
Note:
----
<font size=4>因為<font color=#fc499a> useEffect 會預設處理更新</font>,所以沒有專門用於處理更新的程式碼。在應用下一個 effect 之前,它將清除之前的 effect。為了說明這一點,下面列出該 component 隨時間推移可能產生的一系列訂閱和取消訂閱的呼叫:</font>

<font size=4>而又因為 function component 搭配採用 useState 跟 useEffect 等 hook ,更加貫徹了一律重繪的單向資料流策略,從根本上就確保了程式碼的一致性,避開了 class component 中常見的『由於缺少更新邏輯而導致的 bug』。</font>
----
### 小結
>對於有提供 API 的 class component 來說,需要由 developers 有意識地主動撰寫應用多個 methods。而在漸趨複雜的專案中,useEffect 刻意地同步資料流設計處理副作用,相對更符合宣告式 (declaritive) 程式設計。
---
## 4-3 每次 render 都有自己的 props、state 與 event handler 函式
----
## 4-3-1 每次 render 都有其自己版本的 props 與 state
----
#### <font color=red>誤解</font>
#### React 會去監聽 state 改變進而觸發 re-render?
----
再看一次[流程圖](https://www.figma.com/board/JcwpPwbCHjI86HrfySVp3N/life-cycle-of-function-component?node-id=0%3A1&t=NCmgdOLSy7lCQ9Kz-1)

```
const [imageCount, setImageCount] = useState(0)
```
<font size=5>透過 useState 這個 hook 取到當前的值 => 宣告 const imageCount = 0</font>
Note: 帶流程圖,
觸發 > 呼叫 setState...
1. 利用 setState 儲存新的 state 值在 fiber node 裡
----
再看一次[程式碼](https://codesandbox.io/p/sandbox/4-1-1-life-cycle-example-ftsngf?file=%2Fsrc%2FApp.jsx)
每執行一次 component function,js 機制就會創建一個全新的作用域,因此其中的全新 state 變數 (imageCount) 、每一個相依而生的常數、event Handler 函式...都是該次專屬的,呼應前面各自獨立的實例及其存取的獨有資料。
Note:
[demo hints]
2. 而再次執行 cp fn 的時候,會透過 useState 這個 hook 取到當前的值
3. => 宣告常數 const imageCount = 0,接著利用最新版的 state 變數與相對應有關的 props 重新執行一次 cp fn 。
----
## 4-3-2 每次 render 都有其自己版本的 event handler 函式
eventHandler[程式碼](https://codesandbox.io/p/sandbox/4-3-2-eh-qj2nqh?file=%2Fsrc%2FApp.jsx)
Note:
1. 再次執行該 cp fn 的時候,宣告了一個新的 eH。而連帶宣告內部新的 setTimeout callback fn。
2. 因為 closure 特性,這個 sT cBack fn 可以「記住」該 Componenet function 執行時所對應的 state 跟 props。
3. 延伸結論,每次 render 也有自己版本的 eH、對應到該次的 props 跟 state
4. props 也是一樣的,
----
## 4-3-3 Immutable 資料使得 closure 函式變得可靠而美好
Note: 那就帶領我們到最後一個小節,終於QQ
----
# 回顧
1. 在 fn cp 執行的時候,會捕捉當下的 props, state 等資料,快照形式儲存。
2. 以 event Handler 為例,會因為 closure 的特性,跟每次獨有的資料綁定、可隨時取得可靠的資料。
讓 eH 成為單向資料流的一部分。
----
## 快照

Note: (...前略)剛剛說過在 fn cp 執行的時候,會捕捉當下的 props, state 等資料,以類似快照形式儲存。
----
來點科普:Cyber Security -- Ransomware

Note: 問問大家 Ransomware 是甚麼?有甚麼特性?
勒索 + 軟體
特性:專門竄改資料、加密資料;綁架你的寶貴資料、跟受害人勒索(資料的)贖金。
----
來點科普:Cyber Security -- Ransomware<br>
<span>在眾多對抗勒索軟體的手段中,利用<font color=#1bf58f>快照復原</font>的解決方案是許多大廠皆有提到的重點。正是因為其<font color=#fc499a> immutable </font>的特性,讓 <font color=#fc499a>ransomware 無法竄改</font>過去的快照檔案。透過對 backup data 定期拍攝快照,IT 人員可以利用指定時間當下的快照、快速將系統修復還原。<!-- .element: class="fragment" data-fragment-index="1"--></span>
----
|  | key points: <br>1. 儲存多少張快照<br>2. 最短間隔時間<br>3. 恢復服務的所需時間<br>4. 設備的效能...<br>
| -------- | -------- |
Note: 太多可以講,有興趣的人歡迎多查詢了解
----
# function component 的資料就像快照、真的都是 immutable 的?
設計理念是如此,
但很遺憾地偶爾會出錯,
因為 <span>事在人為<!-- .element: class="fragment" style="color: #fc499a" data-fragment-index="1"--></span>
Note: 前面講到 function component 的特性是自動「捕捉」的資料類似快照。
但資料真的都像快照 immutable 的嗎?
----
If our data was stored in a snapshot
#### mutable data is like...

Portraits in Hogwarts<!-- .element: class="fragment" data-fragment-index="1" -->
Note: 。試想,如果資料會變動,那不是跟哈利波特裡面的畫像一樣了嗎?只能淡淡說一聲:唉,你不能期望照片裡的人物永遠在那裏啊!
----
某些情況之下,props 還是可能被意外修改;例如在巢狀 object 的情況下,developers 不小心修改到下一層的資料。因此,即使有 closure 幫助我們可以取得外部資料,資料流也被破壞了。
這時就<font color=#fc499a>有賴 developers 有意識地避免</font>去 mutate 資料。
----
## 重點回顧
1. 設計理念 props 與 state 就像快照,該是 immutable 的
2. Closure 的精神
3. 延伸的內部函式也會是 immutable
4. 資料流的正確性與可靠性
=> 開發者的責任是要確認資料是 immutable 的,
才可真正大聲說出快照的比喻
----
# WHO?
----

----
# We are THE developers!
Note: 這是我今天最後一張投影片,進入連環題目時間,測測看你的了解~
----
#### 4-3 觀念檢測
1. React 會監聽資料的改變並自動觸發舊有畫面的修改嗎?為什麼? <!-- .element: class="fragment" data-fragment-index="1" -->
2. 為什麼每一次 render 中的 props 與 state 的值都是永遠不變的?<!-- .element: class="fragment" data-fragment-index="2" -->
3. 總結解釋「每次 render 都有其自己版本的 props 與 state」是什麼意思?<!-- .element: class="fragment" data-fragment-index="3" -->
4. 為什麼 component function 內所定義的 event handler 函式可以永遠記得那些存取到的 props 與 state 變數?<!-- .element: class="fragment" data-fragment-index="4" -->
Note: 雖然很多面向重複,但鼓勵每個人用自己的方法精準回答~
----
#### 4-3 觀念檢測
5. Component function 內所定義的 event handler 函式,在每次 render 之間是同一個函式個體嗎?為什麼?<!-- .element: class="fragment" data-fragment-index="5" -->
6. 總結解釋「每次 render 都有其自己版本的 event handler 函式」是什麼意思?<!-- .element: class="fragment" data-fragment-index="6" -->
7. 為什麼 immutable 資料以及 closure 是讓 component 裡的函式也變成單向資料流的一部分的重要關鍵?<!-- .element: class="fragment" data-fragment-index="7" -->
Note: 自己寫個答案在這裡
---
# Thank you :)
---
{"title":"CH.4 Component 的生命週期與資料流","contributors":"[{\"id\":\"5573773d-4d0c-41fa-967d-56aefae1ce8a\",\"add\":30260,\"del\":15594}]","description":"2024/5/15 導讀人:LJBL","slideOptions":"{\"transition\":\"slide\",\"spotlight\":{\"enabled\":true}}"}