來學 React 吧之二_React 重要概念 useEffect


Posted by Christy on 2021-11-05

本文為學習 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 文章

A Complete Guide to 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










Related Posts

[ week 1 ] Markdown 語法筆記

[ week 1 ] Markdown 語法筆記

[ Week 1 ] - Command Line

[ Week 1 ] - Command Line

回溯法(Backtracking)& 分支定界法(Branch and Bound)

回溯法(Backtracking)& 分支定界法(Branch and Bound)


Comments