React之setInterval使用
前端
0
818
0
发表于: 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);
使用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>();
const [count, setCount] = useState(1);
const handleTimer = () => {
setCount(count + 1);
};
useEffect(() => {
countRef.current = handleTimer;
});
useEffect(() => {
if (!started) {
clearInterval(timer);
return;
}
const newTimer = setInterval(() => {
countRef.current();
}, 500);
setTimer(newTimer);
}, [started]);
const clearTimer = () => {
clearInterval(timer);
setStarted(false);
setTimer(null);
};
const add100 = () => {
setCount(count + 100);
};
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);
把逻辑封装成hooks
useInterval
因为是hooks,需要遵循hooks规则:https://zh-hans.reactjs.org/docs/hooks-rules.html
import { useEffect, useRef } from 'react';
export const useInterval = (
callback: any,
delay: number | undefined,
options?: { immediate: boolean }
) => {
const savedCallback = useRef<any>();
savedCallback.current = callback;
useEffect(() => {
if (typeof delay !== 'number' || delay < 0) return;
if (options?.immediate) {
callback();
}
const timer = setInterval(() => {
savedCallback.current();
}, delay);
return () => clearInterval(timer);
}, [delay]);
};
使用
// import { useInterval } from 'ahooks';
import { memo, useState } from 'react';
import { useInterval } from '@/hooks/useInterval';
const Counter = () => {
console.log('Counter组件渲染了');
const [count, setCount] = useState(1);
const [delay, setDelay] = useState<number | undefined>();
function callback() {
setCount(count + 1);
}
useInterval(() => {
callback();
}, delay);
return (
<div>
<div>count:{count}</div>
<button onClick={() => setCount(count + 100)}>加100</button>
<button onClick={() => setDelay(undefined)}>清除定时器</button>
<button onClick={() => setDelay(delay ? undefined : 500)}>
{!delay ? '开始' : '停止'}定时器
</button>
</div>
);
};
export default memo(Counter);
使用useReducer
import { memo, useReducer, useState } from 'react';
const Counter = () => {
console.log('Counter组件渲染了');
const reducer = (state, action) => {
switch (action.type) {
case 'addNum':
return state + action.num;
case 'addOne':
return state + 1;
default:
throw new Error();
}
};
const [count, dispatch] = useReducer(reducer, 1);
const [timer, setTimer] = useState<any>(null);
const add100 = () => {
dispatch({ type: 'addNum', num: 100 });
};
const clearTimer = () => {
clearInterval(timer);
setTimer(null);
};
const switchTimer = (flag) => {
if (!flag) {
clearInterval(timer);
setTimer(null);
return;
}
const newTimer = setInterval(() => {
dispatch({ type: 'addOne' });
}, 500);
setTimer(newTimer);
};
return (
<div>
<div>count:{count}</div>
<button onClick={() => add100()}>加100</button>
<button onClick={() => clearTimer()}>清除定时器</button>
<button onClick={() => switchTimer(!timer ? true : false)}>
{!timer ? '开始' : '停止'}定时器
</button>
</div>
);
};
export default memo(Counter);
最后更新于:2022-04-28 20:12:45
欢迎评论留言~
0/400
支持markdownComments | 0 条留言
登录
按时间
按热度
目前还没有人留言~