[情境劇場]
解師傅:餐廳請了歌手來駐唱,讓生意越來越好了,卻引來了隔壁小吃店的不滿,在我們版上留了負評
小當家:人紅是非多…這也是沒辦法的事,金錢才是王道啊!!
Side Effect 副作用
在介紹 useEffect 先來認識什麼是 Effect,Effect 指的是「Side Effect
」,簡稱 Effect
,中文是副作用的意思。
我們最常聽到的副作用,也就是醫生開藥的藥單上面都會寫哪些藥,上面寫著作用跟副作用,作用是緩解鼻塞、流鼻水,可能會伴隨的副作用是會想睡覺
在 JavaScript 的也是這樣的存在,「在執行函式或行為時,會導致原有的狀態被改變或有附加功能」,就稱之為 Side Effect,例如:改變全域變數狀態、發送 HTTP Request、手動操作 DOM 元素 、改變系統狀態等等
認識 useEffect
useEffect 就是來處理 Side Effect 的 Hook,早期的 Class Component 是使用生命週期 (lifecycle)來管理組件函式,但這讓相同邏輯的函式,被迫拆開在不同的生命週期
1 | class FriendStatus extends React.Component { |
因此 useEffect 的設計在將其保持在一起,易於管理,在程式碼上也較簡潔許多
1 | function FriendStatus(props) { |
useEffect 使用方法
- 從 react 中載入 useEffect
- useEffect 帶入一個函式,函式裡帶入要執行的 effect
- 如有 dependencies,將 dependencies 帶入第二個參數陣列
1. 從 react 中載入 useEffect
1 | import { useEffect } from 'react'; |
2. useEffect 帶入一個函式,函式裡帶入要執行的 effect
1 | useEffect(() => { |
useEffect 會在參數中帶入一個函式,而這個函式會在「畫面渲染完成」後被呼叫,函式裡面放入畫面完成後需要執行的 effect
3. 如有 dependencies,將 dependencies 帶入第二個參數陣列
1 | useEffect(() => { |
useEffect 第二個參數為一個陣列,陣列裡會放入需要重新渲染 effect 的依賴,我們稱之為 dependencies,如 dependencies 有變動,才會重新執行 effect
看個範例
這是一個單純的計數器功能,一開始畫面渲染完畢後,會接著執行 useEffect,執行結束後,一直到變更了 count 的值,才會再執行一次 useEffect
1 | import { useState, useEffect } from "react"; |
嘿!為什麼畫面一開始就渲染兩次 ?
為什麼畫面渲染完畢後,會跑了兩次 console.log?
你可以點擊 src/index.js 檔案,會看到裡面有 Strict Mode
嚴格模式
1 | root.render( |
Strict Mode 在開發模式下,為了檢測到渲染期生命週期的預期之外的 Side Effect,故意調用函式兩次,來幫助我們發現 Side Effect
這些函式有
- Class component
constructor
、render
和shouldComponentUpdate
方法 - Class component 的靜態
getDerivedStateFromProps
方法 - Function component 的內容
- 狀態更新函式(
setState
的第一個參數) - 函數傳遞至
useState
、useMemo
或useReducer
如果我們在 index.js 下了 console.log(”index.js”),會發現 index.js 只渲染了一次
問題就很清楚了,Strict Mode 的開發模式下確實會渲染兩次
Strict Mode 只會在開發模式中執行,故不會調用在正式環境
useEffect 使用的四種方式
1. 只執行在畫面渲染後
1 | useEffect(() => { |
不依賴於任何 props 或 state 的值,不需要重新執行的函式或行為,可以直接傳遞一個空陣列
如果你有學過 Class Component,就會像是 lifecycle 中的 componentDidMount
2. 組件更新就執行
1 | useEffect(() => { |
只要任何組件發生變動就會執行,會像是 class lifecycle 中的 componentDidUpdate
3. 組件 dependencies 有變更才執行
1 | useEffect(() => { |
dependencies 發生改變才執行,如範例中的 count 如有變更,才會觸發 console.log,避免在每次 render 都進行昂貴的計算
4. 清理需被銷毀的函式
清理函式會在組件每次重新渲染時執行,先清除上次留下來的 effect,useEffect 會做的 4 個步驟:
- 判斷第二個參數的陣列是否一樣,如果一樣才會繼續
- 執行上一次存下來的清理函式
- 執行
useEffect
的內容 - 把 清理函式 存下來,供下次使用
1 | useEffect(() => { |
在 useEffect 函式裡 return
一個函式,這個函式就是清除 effect 的函式,就像是 class lifecycle 中的 componentWillUnmount
,如果沒有將 effect 清除,當組件重新渲染,都會執行一個新的事件監聽,這很可能會發生錯誤,也會讓效能下降,常見的需要清除的函式如:setInterval、setTimeout、addEventListener…等
結語
認識了 useEffect 跟使用方法,讓我們得以處理 side effect,useEffect 跟之前的 class lifecycle 相比好寫很多,把相同邏輯放在一起也舒服很多~一起練習看看吧!
Reference
本文為 IT 鐵人賽系列文 你 React 了嗎? 30 天解鎖 React 技能
🚀實體工作坊分享
玩轉 Web頁面的前端技術(HTML/CSS/JS) 一日體驗課
最近時賦學苑開了實體體驗課,即使你對程式碼沒有概念也能上手!Lala 會帶你一起做出一個個人品牌形象網站,帶你快速了解前端的開發流程,快跟我們一起玩轉 Web 吧!🚀線上課程分享
線上課程可以加速學習的時間,省去了不少看文件的時間XD,以下是我推薦的一些課程想學習更多關於前後端的線上課程,可以參考看看。
Hahow
Hahow 有各式各樣類型的課程,而且是無限次數觀看,對學生或上班族而言,不用擔心被時間綁住六角學院
如果你是初學者,非常推薦六角學院哦!剛開始轉職也是上了六角的課,非常的淺顯易懂,最重要的是,隨時還有線上的助教幫你解決問題!
Udemy
Udemy 裡的課程非常的多,品質普遍不錯,且價格都滿實惠的,CP值很高!也是很多工程師推薦的線上課程網站。