useEffect()
useEffect()
使用 Effect 同步 – React 中文文档
useEffect(setup, dependencies?)
在重算繪之後執行,讓React能和外側系統的元素同步
code:javascript
import React, { useEffect } from 'react';
import { createConnection } from './chat.tsx';
const _ChatRoom: React.FC<ChatRoomProps> = ({
url,
roomId,
}: ChatRoomProps) => {
const serverUrl, setServerUrl = useState(url);
const message, setMessage = useState('');
useEffect(() => {
const connection = createConnection(serverUrl, roomId);
connection.connect();
return () => {
connection.disconnect();
};
}, serverUrl, roomId);
}
回傳undefined
React會在Effect執行前完成新畫面的算繪
可以改用useLayoutEffect()
如果會有延遲更新畫面的需求
或是想避免在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 = {
serverUrl: 'https://localhost:1234',
roomId: 'music'
};
function ChatRoom({ roomId }) {
const message, setMessage = useState('');
useEffect(() => {
// 1. 在useEffect()中宣告
const options = {
serverUrl: serverUrl,
roomId: roomId
};
const connection = createConnection(options);
connection.connect();
return () => connection.disconnect();
}, roomId);
如果從親函式的參數傳入,可改為從親函式中解構後傳入
code:javascript
function ChatRoom({ options }) {
const message, setMessage = useState('');
const { roomId, serverUrl } = options;
useEffect(() => {
const connection = createConnection({
roomId: roomId,
serverUrl: serverUrl
});
connection.connect();
return () => connection.disconnect();
}, roomId, serverUrl);
如果從函式傳入,可改為在親函式中宣告函式
code:javascript
useEffect(() => {
// 宣告函式
function createOptions() {
return {
serverUrl: serverUrl,
roomId: roomId
};
}
const options = createOptions();
const connection = createConnection(options);
connection.connect();
return () => connection.disconnect();
}, roomId);
不需要用Effect的情況
更新資料
基於props或state更新state
code:javascript
const firstName, setFirstName = useState('First')
const lastName, setLastName = useState('Last')
// X
const fullName, setFullName = useState('')
useEffect(() => { setFullName(firstName + ' ' + lastName }, firstName, lastName)
// O
const fullName = firstName + ' ' + lastName
進行高計算成本的處理
在prop發生變化時重設所有的state
在prop發生變化時更改state
綁定使用者事件
共用同樣的事件處理邏輯
傳送POST請求
連鎖計算
將狀態變化傳送給親元件
將資料傳送給親元件
訂閱外部的store
そのエフェクトは不要かも – React
你可能不需要 Effect – React 中文文档
你不需要使用effect轉換算繪需要的資料
例如想要在顯示一個清單之前先做篩選
如果使用effect更新state
state更新時
React會先計算好要顯示的內容,並commit到DOM上
之後會執行effect
如果effect也更新了state,整個流程就會重新執行
你不需要使用effect處理使用者事件
例如你想在使用者購買產品時發送一個POST請求與顯示提示
在按鍵的事件處理中,你明確知道會發生什麼
在effect執行中,你卻無法知道用戶做了什麼
所以你應該在對應的事件處理函式中處理使用者事件
需要高成本計算的快取時,可以使用useMemo()取代
取得資料不需要獨立出去到事件處理函式
但會需要一個清理函式,忽略較早的回傳結果
code:diff
useEffect(() => {
+ let ignore = false;
fetchResults(query, page).then(json => {
+ if (!ignore) {
setResults(json);
+ }
});
+ return () => {
+ ignore = true;
+ };
}, query, page);
AbortController
2023-05-03 過激派が教える! useEffectの正しい使い方
2024-07-11 結局 useEffect はいつ使えばいいのか