1. 程式人生 > 實用技巧 >React Hook 之 Effect Hook

React Hook 之 Effect Hook

Effect Hook 可以讓你在函式元件中執行副作用操作(資料獲取,設定訂閱,手動更新元件都屬於副作用)。

首先依然是 引入

import React, { useState, useEffect } from 'react';

使用:

useEffect(() => {
      document.title = 'use effect hook'
})

你可以把 useEffect Hook 看作是 componentDidMountcomponentDidUpdatecomponentWillUnmount 三個函式的組合。
在React 元件中,有兩種副作用操作:需要清除的 和 不需要清除的。

無需清除的 effect

傳送網路請求,變更DOM,記錄日誌都是常見的無需清除的操作。

為什麼在元件內部呼叫 useEffect?
將 useEffect 放在元件內部讓我們可以在 effect 中直接訪問 count state 變數(或其他 props)。我們不需要特殊的 API 來讀取它 —— 它已經儲存在函式作用域中。Hook 使用了 JavaScript 的閉包機制,而不用在 JavaScript 已經提供瞭解決方案的情況下,還引入特定的 React API。

預設情況下,第一次渲染之後,和每次更新之後都會執行。React 保證了每次執行 effect 的同時,DOM 已經更新完畢。

需要清除的 effect

訂閱外部資料來源。這種清除是很重要的,可以防止引起記憶體洩漏。
如果你的 effect 返回一個函式,React 將會在執行清除操作是呼叫它。這就是 effect 可選的清除機制。每個 effect 都可以返回一個清除函式(可以是命名函式也可以是箭頭函式)。
React 會在元件解除安裝的時候執行清除操作。effect 在每次渲染的時候都會執行。這就是為什麼 React 會在執行當前 effect 之前對上一個 effect 進行清除。

使用 Effect 的提示

使用多個 Effect 實現關注點分離

比如:訂閱和取消訂閱,開始定時器和取消定時器
你也可以使用多個 effect。這會將不相關邏輯分離到不同的 effect 中。Hook 允許我們按照程式碼的用途分離它們。React 將按照 effect 宣告的順序依次呼叫元件中的每一個 effect。

useEffect 預設會在呼叫一個新的 effect 之前對前一個 effect 進行清理。

通過跳過 Effect 進行效能優化

雖然每次渲染後都執行清理或者執行 effect 清除,減少了一些bug,但是也可能會導致效能問題。在class 元件中,通過在 componentDidUpdate 中對 prevProps 和 prevState 的比較邏輯解決。在 Effect 中,你可以通知 React 跳過對 effect 的呼叫,只要傳遞陣列作為 useEffect 的第二個可選引數即可:

useEffect(() => {
      document.title = `You click ${count} times`
}, [count]); // 僅在 count 更新時執行這個 effect

如果陣列中有多個元素,即使只有一個元素髮生變化,react 也會執行 effect。
對於有清除操作的 effect 同樣適用。

如果你要使用此優化方式,請確保陣列中包含了所有外部作用域中會隨時間變化並且在 effect 中使用的變數,否則你的程式碼會引用到先前渲染中的舊變數。

如果想執行只執行一次的 effect(僅在元件掛載和解除安裝時執行),可以傳遞一個空陣列([])作為第二個引數。這就告訴 React 你的 effect 不依賴於 props 或 state 中的任何值,所以它永遠都不需要重複執行。

要記住 effect 外部的函式使用了哪些 props 和 state 很難。這也是為什麼 通常你會想要在 effect 內部 去宣告它所需要的函式。 這樣就能容易的看出那個 effect 依賴了元件作用域中的哪些值:

Hook 規則

只在最頂層使用 Hook,不要在迴圈,條件,或者巢狀函式中呼叫 Hook
只在 React 函式中呼叫 Hook,不要在普通的JavaScript函式中呼叫 Hook