本文為學習 React
useEffect
的讀書筆記,參考了 [Day 17 - 即時天氣] 頁面載入時就去請求資料 - useEffect 的基本使用 以及 Lidemy 課程影片從 [FE302] 中的「再戰 todo list 與其他 hooks」開始
分成幾個部分:
一、 useEffect
基礎概念:包含是什麼,用在哪裡,怎麼用、為什麼要用、名詞解釋等等
二、介紹 useLayoutEffect
與 lazy initializer,來理解 hook 執行時的運作過程,大部分情形只會用到 useEffect
三、useEffect
進階概念:clean up fn、自己做一個 hook 進階高級班(適用於未來重構、把介面與邏輯拆開)
四、學習困難及如何排解困難
一、React useEffect
基礎概念
1. useEffect
是什麼跟用在哪裡?
a. useEffect
「render 完以後你想做的事」
b. 「一載入頁面,就更新及時的天氣資料」,這時候就會用到
2. 為什麼要用 useEffect
? 沒有方法可執行 render 結束後想要執行的動作,因此 React 提供了這個 hook。
3. useEffect
怎麼用?
a. 用之前要記得 import
import React, { useState, useEffect } from 'react';
b. useEffect
裡面放一個箭頭函式,再把要執行的事件放在箭頭函式裡
useEffect(() => {
alert(1);
});
c. useEffect()
裡面的參數:
// 第一個傳 arrow fn, 第二個參數是一個叫做 dependencies 的陣列
useEffect(arrow fn, [dependencies])
這裡的重點是組件渲染完後,如果 dependencies 有改變,才會呼叫 useEffect
內的 function;也就是說利用第二個參數,控制 useEffect
執行的時機
4. useEffect
的執行順序:
不管是第一次 render,或是用 useState
重新 render 一次,useEffect
的執行順序都是一樣的:
以下程式碼會依序印出:invoke function component -> render -> execute function in useEffect
// STEP 1:載入 useEffect
import React, { useState, useEffect } from 'react';
import styled from '@emotion/styled';
// ...
const WeatherApp = () => {
console.log('invoke function component');
// useState ...
// STEP 2:使用 useEffect Hook
useEffect(() => {
console.log('execute function in useEffect');
});
// handleClick ...
return (
<Container>
{console.log('render')}
<WeatherCard>
{/* ... */}
</WeatherCard>
</Container>
);
};
export default WeatherApp;
5. 名詞解釋:
以下內容來自 [Day 17 - 即時天氣] 頁面載入時就去請求資料 - useEffect 的基本使用
補充:useEffect 的 effect 指的是什麼
大家可能會好奇 useState
中的 state
指的是保存在 React 組件內部的資料狀態,那 useEffect
中的 effect
又是什麼呢?
這個 effect 指的是 副作用(side-effect) 的意思,在 React 中會把畫面渲染後和 React 本身無關而需要執行的動作稱做「副作用」,這些動作像是「發送 API 請求資料」、「手動更改 DOM 畫面」等等。
副作用(side-effect)又簡稱為 effect,所以就使用 useEffect
這個詞。因為 useEffect
內帶入的函式主要就是要用來處理這些副作用,因此這些帶入 useEffect
內的函式也會被稱作 effect
。
「手動更改 DOM 畫面」指的是透過瀏覽器原生的 API 或其他第三方套件去操作 DOM,而不是透過讓React 組件內
state
改變而更新畫面呈現的方式。
二、[FE302] 課程影片「再戰 todo list 與其他 hooks」開始
1. 初探 useEffect
影片主要在介紹 useEffect
,紀錄一下學習過程以及為什麼一開始聽不懂的原因:
a. 我先把整個影片看了一遍,只懂一個點就是「useEffect」 這個 hook 是「render 完以後要做的事」
b. 接著把影片看了四、五遍,發覺越看越疑惑,似乎完全不能理解老師舉的 localStorage 的例子,因沒有畫面感,不清楚那是什麼。
⇒ 在這裡呢,我掉進了「越是想要弄懂,就越不懂」的無窮迴圈裡面
c. 意識到這件事,開始尋求額外的資源幫助,於是去看了 [Day 17 - 即時天氣] 頁面載入時就去請求資料 - useEffect 的基本使用
d. 由於我在 [FE302] 有好好學習 useState
,因此這篇文章很輕鬆的就看懂了。
結論:
不懂的東西,假設看三遍還不懂,那就是真的不懂了,要停下來找其他的幫助。
無法理解的原因,發現自己是「偏向圖像視覺化」的學生,也就是說,一個東西如果無法在大腦裡面被「抽象轉具體」,那我理解力會比較差。
2. 初探 useLayoutEffect 與 lazy initializer
a. render 是什麼?
對於 render 是什麼有點好奇,因為中文裡面常看到「渲染」,跟英文有點對不上的感覺,看到這篇文章 論 Render 翻譯(算繪/演繹) 才理解。
原作的定義是:「Render 就是指透過電腦程式製作出模型 (或是放在一種整體來說稱為「場景檔」內的眾模型) 影像的一道程序。這道程序主要有兩個步驟,一是電腦計算模型的材質紋理如何與光照、光影著色法...等設置交互影響後結果為何,二就是將成果以像素一點一點地呈現成影像給使用者。」
原作想法是「算繪」比較貼近原意的翻譯,若要有個大方向的概論,那就用「演繹」。
附上文章的結論片段:
「總結以上,個人認為最佳的翻譯是『算繪』,依次是『算圖』,『彩現』,最後是最好別用的『渲染』。
如果真要用一個字眼來涵蓋所有的 render 可能含義,那麼我會建議使用『演繹』,可以表達出『根據前面配置好的東西,推演而出的呈現結果』這樣的感覺;或是『演示』,但演示這個詞語意上大有演戲、示範的成份在,而且又與掩飾同音,可能較不適合。」
b. useLayoutEffect 介紹
useLayoutEffect 是「render 完,瀏覽器 paint 以前」的一個 hook,用白話文說就是,useLayoutEffect 是在畫面出現前更新資料;useEffect 畫面出現以後才執行,因此在看到畫面後可能會有「再次更新」畫面會閃一下的情況發生。
下面的圖很重要,要記下來:
Mount: 把 component 放到畫面上
c. lazy initializer 介紹
某些功能只要執行一次(開啟網頁的第一次),那就可以把初始值寫在 useState 裡面,再用一個箭頭函式把想做的事包在裡面。
const [todos, setTodos] = useState(() => {
...
})
3. 再探 useEffect
a. 執行 cleanup fn 的時機點有兩個:
a.1 要執行下一個 effect 時,把上一個清掉
a.2 component unmount 時把 effect 清掉
b. useEffect
的使用方法:
第一個參數是 arrow fn,裡面放想做的事;第二個參數 dependencies 有改變,才會呼叫 arrow fn
clean up fn 則是寫在中間
useEffect(() => {
// wanna do sth here
...
// clean up fn
return () => {
...
}
}, [dependencies])
c. 推薦 useEffect
文章
How Are Function Components Different from Classes?
重要概念補充:hooks 絕對不可以包在 if...else...或 for each 裡面
4. 寫一個自己的 hook!
這是一個教學示範,可以自己做一個 hook 喔,適合以後想要讓程式碼更精簡,重構的時候用,不會也沒關係,知道有這件事就好了。
a. hook 只是一個函式,自己做一個 custom hook,就是另外開一個檔案,命名用 use 開頭
b. 引入該 hook,並且呼叫那個函式
// useTodos 就是一個自製 hook
const [todos, setTodos] = useTodos();
c. 這樣寫,邏輯跟介面是分開的,而且邏輯可以重複利用在別的專案上,介面可以完全不同。好酷!
5. 總結
usehooks: 別人寫好的 hook