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...] : 用來比對stateprops狀態,如果狀態有變,執行function,比對項目如果有多組,只要一個有變,function就會執行。

這裡要提到兩個重要概念:React render 順序dependency比對標準

(一) React render 順序

  • 觀察render順序:
    我們利用 console.log() 分別寫在三個位置:一進入 componentuseEffect()內、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