useEffect()
useEffect(setup, dependencies?)
在重算繪之後執行,讓React能和外側系統的元素同步
code:javascript
import React, { useEffect } from 'react';
import { createConnection } from './chat.tsx';
const _ChatRoom: React.FC<ChatRoomProps> = ({
url,
roomId,
}: ChatRoomProps) => {
useEffect(() => {
const connection = createConnection(serverUrl, roomId);
connection.connect();
return () => {
connection.disconnect();
};
}
React會在Effect執行前完成新畫面的算繪
如果會有延遲更新畫面的需求
或是想避免在Effect之中重算繪狀態更新前的畫面
setup
Effect的執行函式
可以回傳清理函式
元件加入DOM時,會執行setup函式
mount(首次算繪)、重新算繪後
元件從DOM移除時,會執行清理函式
重新算繪前、unmount
清理函式
當dependencies的值改變、發生重算繪時
清理函式會執行舊的值
setup函式會執行新的值
dependencies
所有傳入setup的參數
若無傳入值,每次算繪時都會執行
預設,但容易導致預料之外行為,因此較少使用
useEffect(fn)
若有傳入值,初次算繪和每次dependencies的值改變時都會執行
useEffect(fn, [a, b])
如果是setup函式有用到的值,就可直接一同傳入dependencies內
若傳入空值,useEffect()只會在初次重新算繪之後執行
useEffect(fn, [])
若傳入Object、函式,可能會在意料之外的狀況造成重新執行 可
改至在useEffect()中宣告Object
宣告於親函式外側
code:javascript
// 2. 在親函式外宣告
const options = {
roomId: 'music'
};
function ChatRoom({ roomId }) {
useEffect(() => {
// 1. 在useEffect()中宣告
const options = {
serverUrl: serverUrl,
roomId: roomId
};
const connection = createConnection(options);
connection.connect();
return () => connection.disconnect();
如果從親函式的參數傳入,可改為從親函式中解構後傳入
code:javascript
function ChatRoom({ options }) {
const { roomId, serverUrl } = options;
useEffect(() => {
const connection = createConnection({
roomId: roomId,
serverUrl: serverUrl
});
connection.connect();
return () => connection.disconnect();
如果從函式傳入,可改為在親函式中宣告函式
code:javascript
useEffect(() => {
// 宣告函式
function createOptions() {
return {
serverUrl: serverUrl,
roomId: roomId
};
}
const options = createOptions();
const connection = createConnection(options);
connection.connect();
return () => connection.disconnect();
不需要用Effect的情況
更新資料
基於props或state更新state
code:javascript
// X
// O
const fullName = firstName + ' ' + lastName
進行高計算成本的處理
在prop發生變化時重設所有的state
在prop發生變化時更改state
綁定使用者事件
共用同樣的事件處理邏輯
傳送POST請求
連鎖計算
將狀態變化傳送給親元件
將資料傳送給親元件
訂閱外部的store
你不需要使用effect轉換算繪需要的資料
例如想要在顯示一個清單之前先做篩選
如果使用effect更新state
state更新時
React會先計算好要顯示的內容,並commit到DOM上
之後會執行effect
如果effect也更新了state,整個流程就會重新執行
你不需要使用effect處理使用者事件
例如你想在使用者購買產品時發送一個POST請求與顯示提示
在按鍵的事件處理中,你明確知道會發生什麼
在effect執行中,你卻無法知道用戶做了什麼
所以你應該在對應的事件處理函式中處理使用者事件
取得資料不需要獨立出去到事件處理函式
但會需要一個清理函式,忽略較早的回傳結果
code:diff
useEffect(() => {
+ let ignore = false;
fetchResults(query, page).then(json => {
+ if (!ignore) {
setResults(json);
+ }
});
+ return () => {
+ ignore = true;
+ };