---
# System prepended metadata

title: useEffect的作用跟相對應的功能

---

# useEffect的作用跟相對應的功能
1. `useEffect` ≒ `componentDidMount`+`componentDidUpdate`+`componentWillUnmount`
2. 對應的功能：
`useEffect`接收兩個參數。

    - 第一個是一個函式：
        - 定義 `componentDidMount` 或 `componentDidUpdate` 時要做什麼事
        - 此函式的 return 值也要是一個函式，表示 `componentWillUnmount` 時要做什麼事

    - 第二個是一個array (dependencies)：
        - 定義當哪些**變數被改變**時，這個 `useEffect` 要重新被觸發。
        
    ---
    
    1. `componentWillUnmount`：如果你的 effect 回傳了一個 function，React 將在需要cleanup時執行它
    2. `componentDidMount`：想執行一個 effect 並且僅（在 mount 和 unmount 時）將其執行一次，則可以傳遞一個空 array（[]）作為第二個參數。這告訴 React 你的 effect 不依賴於任何 props 或 state 的值，因此它不需要重新執行。
    3. `componentDidUpdate`：確保 第二個參數的 array 包括了 component 範圍內隨時間變化並被 effect 用到的所有值（例如 props 和 state）。否則，你的程式碼將引用先前 render 中的舊值。

3. 每次 render 後都會執行 useEffect 嗎：
    >是的！預設情況下，它在第一個 render 和隨後每一個更新之後執行


    :::info
    把 effect 想成發生在「render 之後」
    :::
    
4. useEffect 就是在做 side effect 的操作
    :::info
    side effect
    1. 資料 fetch
    2. 設定 subscription (需要cleanup)
    3. 手動改變 React component 中的 DOM
    :::

5. cleanup:
    cleanup在每次**重新render**時都會執行（執行的時間點在執行render前），而不是只在 unmount 組件的時候執行。
    
    :::info
    為什麼有些side effect不需要cleanup：因為執行之後就可以被忽略 (幫QQ)
    :::
    
    - 做了cleanup的例子 (以下使用class component)：
        這個 component 顯示朋友是否在線上。我們的 class 從 `this.props` 中抓取 `friend.id`，在 component mount 後訂閱好友狀態，並在 unmount 期間取消訂閱：
        ```jsx=
        componentDidMount() {
            ChatAPI.subscribeToFriendStatus(
              this.props.friend.id,
              this.handleStatusChange
            );
        }

        componentWillUnmount() { 
        ChatAPI.unsubscribeFromFriendStatus(
              this.props.friend.id,
              this.handleStatusChange
            );
        }
        ```

        **但是如果 component 顯示在螢幕上時，friend prop 發生變化，會發生什麼呢？**
        :::warning

        Unmount 時，取消訂閱的呼叫會使用錯誤的朋友 ID (造成 memory leak 或 crash)
        :::
6. 對比 useEffect 和生命週期：
    :::warning
    不建議用生命週期的思路去類比思考 useEffect 的執行過程，因爲 useEffect 的執行模式和 componentDidMount 等其他生命週期是不同的
    :::
    
    - `useEffect` 可以被看作是每一次渲染之後的一個獨立的函數 ，可以接收 `props` 和 `state` ，並且接收的 `props` 和 `state` 是當次 render 的數據，是獨立的。
    - 生命週期 `componentDidMount` 中的 `this.state` 始終指向最新數據


    :::info
    `useEffect` 中不一定是最新的數據，更像是render結果的一部分 (因此才會說 `useEffect` 不會阻止瀏覽器更新螢幕)
    :::
    
7. `useEffect` 和 `useLayoutEffect` 的區別
    > `useLayoutEffect` 的使用方法和 `useEffect` 相同，區別是他們的執行時機（以及是否同步執行）。
    - `useEffect` 的內容是會在 DOM render 之後執行 (非同步)
    - `useLayoutEffect` 是在瀏覽器render之前被同步執行 (同步)
例如：在瀏覽器執行下一次render前，需要操作 DOM 改變頁面樣式，如果放在 useEffect 中執行，會出現閃屏問題。