前言
其实关于这个问题在知乎和百度上都有提及,但是在掘金上却没有详细的文章,因此准备出一篇文章来解决在useEffect中如何使用定时器。有一篇文章写得特别好,如果大家想深入理解可以点击此链接 使用 React Hooks 声明 setInterval
眉头一皱,发现问题并不简单
首先让我们做一个小Demo,设置一个名为value的state,并每隔5秒,产生一个随机数,并让value加上这个数
import React, { useState, useEffect } from 'react';
import './App.css';
function App() {
const [value, setValue] = useState<number>(0);
useEffect(() => {
const timer: NodeJS.Timeout = setInterval(() => {
const random = (Math.random() * 10) | 0;
setValue(value + random);
}, 5000);
return () => {
clearInterval(timer);
};
}, []);
return <div>{value}</div>;
}
export default App;
你自信满满的打开了浏览器,too simple! 突然发现了value的值只发生了一次变化,你检查发现,原来useEffect的依赖性并没有填入,于是你小心翼翼的将value填入依赖性
useEffect(() => {
// .....
}, [value]);
perfect!,代码如期执行,每隔5秒都会增加一个值,心里想着‘不愧是我!’
你以为的你以为的不是你以为的
如果我们在代码中加入一个定时器数组,用来记录你添加了多少个定时器
function App() {
const [value, setValue] = useState<number>(0);
const [timers, setTimers] = useState<Array<NodeJS.Timeout>>([]);
useEffect(() => {
const timer: NodeJS.Timeout = setInterval(() => {
const random = (Math.random() * 10) | 0;
setValue(value + random);
}, 5000);
timers.push(timer);
setTimers(timers);
console.log(timers);
return () => {
clearInterval(timer);
};
}, [value]);
return <div>{value}</div>;
}
你会惊讶的发现你不仅value发生变化了,而且又多生成了一个定时器。如下图所示。

不要慌,问题不大
为了解决这个问题,我们需要引入react中另外一个hook ,useRef。useRef 返回一个可变的 ref 对象,其 .current 属性被初始化为传入的参数(initialValue)。返回的 ref 对象在组件的整个生命周期内保持不变,利用这个特性,我们把它用在我们的demo中看看效果
function App() {
const [value, setValue] = useState<number>(0);
const [timers, setTimers] = useState<Array<NodeJS.Timeout>>([]);
const saveCallBack: any = useRef();
const callBack = () => {
const random: number = (Math.random() * 10) | 0;
setValue(value + random);
};
useEffect(() => {
saveCallBack.current = callBack;
return () => {};
});
useEffect(() => {
const tick = () => {
saveCallBack.current();
};
const timer: NodeJS.Timeout = setInterval(tick, 5000);
timers.push(timer);
setTimers(timers);
console.log(timers);
return () => {
clearInterval(timer);
};
}, []);
return <div>{value}</div>;
}
使用了useRef后,定时器不会被重复创建,但是value的值变成了依次累加,达到了预期的效果,真是让人神清气爽,so cool!