React之setInterval使用
发表于: 2022-04-28 20:12:45
简介: 学了,但完全没有学
前言
学习以及使用一门技术这么长时间,却连它的官方文档都没看过几次,是可笑还是可悲。
取巧的实现
取巧的实现,而且有局限性。
import { memo, useEffect, useState } from 'react';
const Counter = () => {
console.log('Counter组件渲染了');
const [count, setCount] = useState(1);
const [started, setStarted] = useState(false);
const [timer, setTimer] = useState<any>();
// useEffect没有传入依赖数组,说明每次Counter组件渲染都会执行
// 利用这一点,就可以每次渲染时开始定时器,并且通过返回函数清楚定时器副作用实现
// 缺点:因为是依赖于每次渲染,才开始定时器的,如果我一直手动点击加100的按钮,Counter组件就会不断渲染,
// 期间里面的定时器就会不断的开始定时器,还没等到定时器执行完,就因为渲染问题立即清除了定时器(因为我是一直点击加100的按钮,一直渲染的)
// 因此,只有等我不点击加100的按钮了,才会继续执行定时器。即这个定时器的逻辑是和我点击加100的行为冲突的,
// 做不到我一边点击加100的按钮,这个定时器也做自己的逻辑。
useEffect(() => {
if (!started) return;
const timer = setInterval(() => {
console.log('此时的count', count); //这个count是最新的
setCount(count + 1);
setTimer(timer);
}, 500);
// setTimer(timer); //不能在这里设置,会死循环。
return () => clearInterval(timer);
});
const clearTimer = () => {
setStarted(false);
clearInterval(timer);
};
return (
<div>
<div>count:{count}</div>
<button onClick={() => setStarted(!started)}>
{!started ? '开始' : '停止'}定时器
</button>
<button onClick={() => setCount(count + 100)}>加100</button>
<button onClick={() => clearTimer()}>清楚定时器</button>
</div>
);
};
export default memo(Counter);
使用函数式更新实现
https://zh-hans.reactjs.org/docs/hooks-reference.html#functional-updates
import { memo, useEffect, useState } from 'react';
const Counter = () => {
console.log('Counter组件渲染了');
const [count, setCount] = useState(1);
const [timer, setTimer] = useState<any>(null);
const [started, setStarted] = useState(false);
const handleTimer = () => {
const newTimer = setInterval(() => {
console.log('此时的count', count); //这个count引的是外层的count(闭包)他的值往往不是最新的。
setCount((preVal) => {
console.log('preVal', preVal); //这个preVal是上一次更新的值
return preVal + 1; //返回值是更新后的值
});
}, 500);
setTimer(newTimer);
};
useEffect(() => {
if (!started) {
clearInterval(timer);
return;
}
handleTimer();
}, [started]);
const clearTimer = () => {
clearInterval(timer);
setStarted(false);
setTimer(null);
};
return (
<div>
<div>count:{count}</div>
<button onClick={() => setCount(count + 100)}>加100</button>
<button onClick={() => clearTimer()}>清楚定时器</button>
<button onClick={() => setStarted(!started)}>
{!started ? '开始' : '停止'}定时器
</button>
</div>
);
};
export default memo(Counter);
使用useRef实现一
import { memo, useEffect, useRef, useState } from 'react';
const Counter = () => {
console.log('Counter组件渲染了');
const [timer, setTimer] = useState<any>(null);
const [started, setStarted] = useState(false);
const countRef = useRef<any>(1);
const [count, setCount] = useState(countRef.current);
const handleTimer = () => {
const newTimer = setInterval(() => {
console.log('此时的count', count); //这个count引的是外层的count(闭包)他的值往往不是最新的。
countRef.current = countRef.current + 1; //这个countRef.current会更新,但是不会响应到hooks,我们可以setCount(countRef.current)响应到count
console.log(countRef.current);
setCount(countRef.current);
}, 500);
setTimer(newTimer);
};
useEffect(() => {
if (!started) {
clearInterval(timer);
return;
}
handleTimer();
}, [started]);
const clearTimer = () => {
clearInterval(timer);
setStarted(false);
setTimer(null);
};
const add100 = () => {
countRef.current = countRef.current + 100;
setCount(countRef.current);
};
return (
<div>
<div>count:{count}</div>
<button onClick={() => add100()}>加100</button>
<button onClick={() => clearTimer()}>清楚定时器</button>
<button onClick={() => setStarted(!started)}>
{!started ? '开始' : '停止'}定时器
</button>
</div>
);
};
export default memo(Counter);