[誰來跟我 React 一下] useEffect Hook 1:基礎使用與 JSON Server

控制函式跑動次數、fetch JSON data、條件渲染

YiChe Liu
9 min readMar 22, 2022

除了前面介紹過的 useState 外, React 還提供許多實用的 Hook ,例如本篇主角: useEffect 。我們一樣繼續沿用前兩篇的範例,若是空降此篇的觀眾,建議先將範例打開才不會看不懂喔。

關於 useEffect 與生命週期的關係,我補充在 [誰來跟我 React 一下] 生命週期與 useEffect 裡。

基礎使用

只要元件內容被更改(不論是初始化,還是 state 資料有所更新), useEffect 就會執行一次函式。當我們需要在每次資料更新時做某件事,就可以使用它。

馬上來看看簡單的寫法範例:

藉由觀察程式碼運行的狀況,可再次驗證畫面第一次被渲染時,或資料被 handleDelete 刪除時,都會跑 useEffect 裡的函式印出對應字樣。

控制次數

我們能藉由在第二個參數加入空陣列,控制讓 useEffect 裡的函式只跑一次。但如果好幾筆 state 資料,有的要只跑一次、有的要每次更動都跑,則可以在該陣列中加入每次都要跑的 state 名稱。

用文字敘述有點繞口,讓我們直接來看程式碼:

以上面的程式碼來說,我們設定了兩筆 state ,一筆是 menu 、一筆是 name 。由於我們在 useEffect 第二個參數中的空陣列指定 name ,因此只會監聽 name 這個 state 有無被改變。當改變時,才會跑 useEffect 第一個參數裡的函式。也就是說:

當頁面被載入時, console 面板會印出 effect done 和 apple ,接下來刪掉 menu 的內容並不會讓 useEffect 裡的函式被執行,但若去按 change name 的按鈕, console 面板則會再次印出 effect done 以及新的 name 值 banana 。由於我們沒有寫 troggle name 的相關程式碼, state 不管按了幾次按鈕,都只會停在 banana 不會再變回 apple ,所以useEffect 也不會再跑第三次。不過你可以試著改寫看看,再用 console 觀察 useEffect 跑動的情形。

JSON Server 抓資料

現在你已經了解 useEffect 觸發條件,但可能還是不太清楚怎樣的狀況下會運用到它。其實最簡單的其中一個例子,就是在元件抓取遠端資料,也許是 JSON 資料、 RESTful API 等等。總之每當元件重新渲染、亦或資料更動時,我要抓到最新資料。

在此之前我們的資料都是直接放在程式碼中,現在終於能把資料移出去啦!

如果你已經有現成 API ,可以跳過這段。如果沒有,那我們可以使用 JSON Server 來做一個簡單的模擬。

首先在專案根目錄新增一個資料夾 data ,在裡頭放一個 db.json 的檔案,並將你的資料放進來。

menu 這個名稱等等會作為網址顯示,不會出現在資料中

接著你可以選擇把 JSON Server Package 下載下來使用,或直接用 npx 。如果要直接使用 npx ,按+打開另一個終端機,輸入:

npx json-server --watch data/db.json --port 8000

讓他監聽 data 資料夾下的 db.json ,並在 port 8000 跑。之所以要這樣是因為我們同時在用 port 3000 跑 react … 如果你沒有開另一個終端機跑 db.json ,直接 ctrl+c 暫停 react 然後跑 db.json ,那 react 就被暫停了,即使資料庫跑起來也無法看到正確畫面。同理,如果你沒有另外設 port 8000 ,他可能會照預設往 port 3000 去跑,會跟正在 port 3000 跑的 react 衝到。為什麼要解釋這麼多呢?因為我就卡在這個低級錯誤裡卡了半小時顆顆。

按下 enter 若成功應該這樣顯示

按 enter 後如果有成功,可以點進 Resources 下的網址看看。應該會看到一串資料。

驗證剛剛所說, menu 這個名稱只出現在網址,不會出現在資料中

JSON Server 介紹結束,有 API 的各位可以從這裡繼續讀下去了。

在此想藉由 useEffect ,讓元件在第一次渲染時,使用 fetch 取得資料並更新為 menu 。

首先要定義 menu 和 setMenu ,初始化其為 null 。接著則用 useEffect 搭配 fetch 來抓資料,抓到後用 setMenu 將 menu 更新。這裡有個小細節要注意!因為我們初始化將 menu 設為 null ,會導致 return 裡要跑 MenuList 元件 map 函式時出現錯誤… 下面已直接列出解決辦法,不過我會在下一塊做更完整的解釋。

剛跟我們一起用 JSON Server 的朋友們, url 請放 http://localhost:8000/menu/

條件渲染

有時會需要依條件做渲染,在 Vue 裡可以使用 v-if ,在 React 則須透過原生 JS 來達成。例如上面的例子,若 menu 是 null ,則不要繼續讓程式嘗試渲染畫面,會因為取不到值報錯。

要在 JSX 中撰寫 JS ,外面要先加上大括號。在裡頭使用 && ,讓左方成立時,才去檢查右方是否成立,進而避免報錯產生。同時,當左方成立,右方也成立時,畫面上也只會渲染右方的程式碼。

同理,我們也可以在資料還沒被取得時,讓畫面出現「載入中…」的文字,或抓不到資料、有錯誤訊息時,直接印在畫面上讓使用者知道,就像下面那樣:

在上面的程式碼中,我們預設 error 一開始為空,代表正常情況下沒有錯誤訊息; isPending 是 true ,代表一開始畫面必須先出現「載入中…」。取得資料不論成功、報錯,將 isPending 設為 false 好讓載入的文字消失。若取得資料是報錯的,要將 error 這筆資料填入報錯的內容;反之若取得成功,則將 setError 調回預設值,以免一度錯誤後就一直呈現錯誤訊息在畫面上。

也可以使用 || 來處理預設值,例如當沒抓到對應資料時,就顯示預設:

太習慣使用 v-for v-if 等,練習 React 時腦子常一時之間轉不過來。

系列連結

Medium 不太好找前後篇文章,所以在這個系列文章最後,放入任意門連結,希望能幫助到你!

--

--

YiChe Liu
YiChe Liu

Written by YiChe Liu

小菜鳥前端 / 親手打過的筆記才是自己的

No responses yet