昨天我們學習了副作用相關的知識,並嘗試使用useEffect完成了一個小練習,但還沒有使用到cleanup function。今天要透過實作的練習來學習Cleanup function的相關知識。
今天會學到的東西:
現有的程式碼:
import React from 'react';
import Clock from './Clock'
function App() {
const [showClock, setShowClock] = React.useState(true);
return (
<>
<button
className="clock-toggle"
onClick={() => setShowClock(!showClock)}
>
{showClock ? 'Clock ON' : 'Clock OFF'}
</button>
{showClock && <Clock />}
</>
);
}
export default App;
import React from 'react';
import format from 'date-fns/format';
function Clock() {
const [time, setTime] = React.useState(new Date());
return (
<p className="clock">
{format(time, 'hh:mm:ss a')}
</p>
);
}
export default Clock;
本次的練習僅需要操作Clock.js
的檔案即可。
畫面是這個樣子,當點擊按鈕時,會顯示/隱藏 電子時鐘。
像這樣子時鐘會被隱藏,要做到一旦顯示時,則時鐘正常的運作。
要做時鐘我們會用到的有setInterval,而setInterval的操作也是屬於副作用的一種,因此需要使用useEffect function。
React.useEffect(()=> {
//要執行的程式碼
}, [])
因為希望當點擊按鈕時,電子時鐘出現,這樣子的情況應採用dependencies 為 []
empty string的作法,也就是「程式碼僅在**掛載(mounting)時執行(當元件出現時)」(這部分昨天的文章有提到)。
React.useEffect(()=> {
const intervalID = window.setInterval(()=> {
setTime(new Date());
}, 1000)
}, [])
在內部使用了一個定時器(setInterval
),每隔一秒執行一次,讓每秒能夠更新一次時間。
目前為止電子時鐘看起來似乎正常運作了,也顯示了正確的時間。
但當我們把時鐘收合起來,程式碼真的就沒有在運作了嗎?
讓我們在setInterval當中測試看看:
React.useEffect(()=> {
const intervalID = window.setInterval(()=> {
console.log('滴答');
setTime(new Date());
}, 1000)
}, [])
加入了秒針的滴答聲,接下來把時鐘收合起來看看:
可以發現即使把按鈕收合起來,仍然在「滴答滴答~」,也就是setInterval 還在運作中,並沒有因為將按鈕收合起來而停止運作。
為什麼會這樣子呢?如果是unmount 不是應該要自動被卸載嗎?
這是因為React其實不知道useEffect內部發生什麼事,當在一個元件中使用了useEffect
處理副作用,元件渲染時,React並不知道內部做了什麼事情。它只知道在指定的時機(由設定的dependencies)來呼叫我們寫在useEffect
中的function。
對React 而言,React看到的就是這樣子:
// React看見的世界:
React.useEffect(() => {
????
}, []);
因為React並不知道,因此需要另外設置讓setInterval停止的操作,需要cleanUp function來設定。
cleanup function的寫法是透過在useEffect function中 return function來處理:
return () => {
// function的內容
};
那我們來加上cleanup function到電子時鐘上:
React.useEffect(() => {
const intervalID = window.setInterval(() => {
console.log('滴答');
setTime(new Date());
}, 1000);
return () => {
clearInterval(intervalID)
}
}, []);
再來觀察看看關閉電子時鐘還會有滴答聲嗎?
滴答聲消失了,這代表我們成功clearInterval,這樣就完成電子時鐘。
以上是今天的練習,今天學到為什麼需要cleanup function以及練習了cleanup function的寫法。
雖然在這個時鐘案例我們使用了cleanup function,但並不是每次操作useEffect都需要 cleanup function的操作,cleanup function通常用在訂閱事件、設置定時器、綁定事件監聽器等的操作,而像是一次性操作或是有外部自動清理機制的操作等並不需要cleanup function。
(本日練習出自The Joy of React)