若在按时器内间接利用 React 的代码,可能会收到意想不到的成果。如我们想实现一个每 1 秒加 1 的按时器:

const App = () => { const [count, setCount] = useState(0); useEffect(() => { const timer = setInterval(() => { setCount(count + 1); }, 1000); return () => clearInterval(timer); }, []); return <div className="App">{count}</div>;};

能够看到,coun 从 0 酿成 1 以后,就再也稳定了。为什么会如许?

如何实现一个定时器的 hook  第1张

虽然因为按时器的存在,组件始末会不断从头衬着,但按时器的回调函数是挂载期间定义的,所以它的闭包永久是对挂载时 Counter 感化域的引用,故 count 永久不会超越 1。

针对那个单一的 hook 挪用,还比力好处理,例如能够监听 count 的变革,或者通过 useState 的 callback 传参体例。

const App = () => { const [count, setCount] = useState(0); // 监听 count 的变革,不外那里将按时器改成了 setTimeout // 即便不修改,setInterval()的timer也会在每次衬着时被肃清掉, // 然后从头启动一个新的按时器 useEffect(() => { const timer = setTimeout(() => { setCount(count + 1); }, 1000); return () => clearInterval(timer); }, [count]); // 以回调的体例 // 回调的体例,管帐算回调的成果,然后做为下次更新的初始值 // 详情可见: https://www.xiabingbao.com/post/react/react-usestate-rn5bc0.html#5.+updateReducer useEffect(() => { const timer = setInterval(() => { setCount(count => count + 1); }, 1000); return () => clearInterval(timer); }, []); return <div className="App">{count}</div>;};

当然还有此外体例也能够实现 count 的更新。那如果挪用更多的 hook,或者更复杂的代码,该怎么办呢?那里我们能够封拆一个新的 hook 来利用:

COPYJAVASCRIPT// https://overreacted.io/zh-hans/making-setinterval-declarative-with-react-hooks/const useInterval = (callback: () => void, delay: number | null): void => { const saveDCallback = useRef(callback); useEffect(() => { savedCallback.current = callback; }); useEffect(() => { function tick() { savedCallback.current(); } if (delay !== null) { const id = setInterval(tick, delay); return () => clearInterval(id); } }, [delay]);};