useEffect 使用時機
這裡的
Effect
指的是「side-effect 副作用」。
也就是說
useEffect
是用來處理React
component
職責以外的
額外動作
。
(舉手提問) React component的職責是什麼?
答:在使用者介面上直接操作資料狀態及回傳節點
。
就是之前說的:實現 相關UI與邏輯 群組化(
component
),並回傳React element(
JSX
)。
(補充後面動作:節點透過
ReactDOM.render()
放入html檔,瀏覽器解析成 DOM tree,然後渲染成網頁畫面。)
額外動作好比:call api拿資料,直接操作原始DOM(不經過React
component
),登入 token...等,不是
component
的主要職責,但需要執行的動作,都可能使用到
useEffect
。
useEffect syntax
useEffect(function,[state1, props2...])
useEffect()接收兩個參數:
function : 執行動作的函式。useEffect()會寫在component裡面,所以函式內也可以操作state
[state1, props2...] : 用來比對state或props狀態,如果狀態有變,執行function,比對項目如果有多組,只要一個有變,function就會執行。
這裡要提到兩個重要概念:React render 順序、dependency比對標準
(一) React render 順序
觀察render順序:
我們利用 console.log() 分別寫在三個位置:一進入 component、useEffect()內、JSX內。
顯示順序:
可以看到component會先屢行它的主要職責,才進行額外行動:useEffect是在component渲染完後才執行。
利用render順序來判斷 : 有無[dependency],程式執行的情況。
(二) dependency比對標準: Object.is
OK,那如果dependency要比對物件型別呢?
useEffect(() => console.log("useEffect !"),[{id: 1, name: "Joanna"}])
這會出現一個狀況:如果物件內的屬性改值,但 useEffect()比對物件的位址不變,導致不會執行動作。
如果要解決這樣的問題,有幾個解決方法:
dependency寫到 物件.屬性 (但屬性值要是基礎型別才有效)
const [obj, setObj] = useState({id: 1, name: "Joanna"});
useEffect(() => console.log("useEffect !"),[obj.name])
既然useEffect()比對物件的位址,那我改位址可以吧!
const [obj, setObj] = useState({id: 1, name: "Joanna"});
useEffect(() => console.log("useEffect !"),[obj])
// 改值:
setObj({...obj, name: "David"})
React官網 - useEffect
UseEffect dependency array and object comparison!
TBD - useEffect dependency comparison