本文由雲+社區發表 作者:Dan Abramov 接觸 "React Hooks" 一定時間的你,也許會碰到一個神奇的問題: "用起來沒你想的簡單" 。 Ryan Florence 在 "他的推文" 裡面說到: 不少朋友跟我提起,setInterval 和 hooks 一起用的時候,有種蛋蛋的憂傷。 ...
本文由雲+社區發表
作者:Dan Abramov
接觸 React Hooks 一定時間的你,也許會碰到一個神奇的問題: setInterval
用起來沒你想的簡單。
Ryan Florence 在他的推文裡面說到:
不少朋友跟我提起,setInterval 和 hooks 一起用的時候,有種蛋蛋的憂傷。
老實說,這些朋友也不是胡扯。剛開始接觸 Hooks 的時候,確實還挺讓人疑惑的。
但我認為談不上 Hooks 的毛病,而是 React 編程模型和 setInterval
之間的一種模式差異。相比類(Class),Hooks 更貼近 React 編程模型,使得這種差異更加突出。
雖然有點繞,但是讓兩者和諧相處的方法,還是有的。
本文就來探索一下,如何讓 setInterval 和 Hooks 和諧地玩耍,為什麼是這種方式,以及這種方式給你帶來了什麼新能力。
聲明:本文采用循序漸進的示例來解釋問題。所以有一些示例雖然看起來可以有捷徑可走,但是我們還是一步步來。
如果你是 Hooks 新手,不太明白我在糾結啥,不妨讀一下 React Hooks 的介紹和官方文檔。本文假設讀者已經使用 Hooks 超過一個小時。
代碼呢?
通過下麵的方式,我們可以輕鬆地實現一個每秒自增的計數器:
import React, { useState, useEffect, useRef } from 'react';
function Counter() {
let [count, setCount] = useState(0);
useInterval(() => {
// Your custom logic here
setCount(count + 1);
}, 1000);
return <h1>{count}</h1>;
}
上述 useInterval
並不是內置的 React Hook,而是我實現的一個自定義 Hook:
import React, { useState, useEffect, useRef } from 'react';
function useInterval(callback, delay) {
const savedCallback = useRef();
// Remember the latest callback.
useEffect(() => {
savedCallback.current = callback;
});
// Set up the interval.
useEffect(() => {
function tick() {
savedCallback.current();
}
if (delay !== null) {
let id = setInterval(tick, delay);
return () => clearInterval(id);
}
}, [delay]);
}
(如果你在錯過了,這裡也有一個一樣的 CodeSandbox 線上示例)
我實現的 useInterval Hook 設置了一個計時器,並且在組件 unmount 的時候清理掉了。 這是通過組件生命周期上綁定 setInterval
與 clearInterval
的組合完成的。
這是一份可以在項目中隨意複製粘貼的實現,你甚至可以發佈到 NPM 上。
不關心為什麼這樣實現的讀者,就不用繼續閱讀了。下麵的內容是為希望深入理解 React Hooks 的讀者而準備的。