我试图了解新的React钩子及其用例。
我的目标是单个组件向上计数,每个x滴答声也计数另一个计数器。
我已经使用useEffect和useState实现了它,但有两个主要问题:
1.在调用超时之前卸载组件时发生内存泄漏(使用react-router导航时)
2.该组件在每个刻度上渲染两次,因为useEffect和useState都触发渲染。
我认为解决方案将是useRef或useMemo的解决方案,但我还没有弄清楚。
我当前的组件(带有打字稿):
import React from "react";
const Component: React.FC = () => {
const [trigger, setTrigger] = React.useState(0);
const [timer, setTimer] = React.useState({ cycle: 0, count: 0 });
let refTimer = React.useRef({ cycle: 0, count: 0 });
// useRef
// React.useEffect(() => {
// setInterval(() => {
// console.log("tick");
// if (refTimer.current.count % 2 === 0) {
// refTimer.current.cycle++;
// setTimer(refTimer.current);
// }
// refTimer.current.count++;
// setTimer(refTimer.current);
// // console.log(timer);
// }, 1000);
// }, []);
// useState
React.useEffect(() => {
console.log("effect tick");
setTimeout(() => {
console.log("tick");
const count = timer.count + 1;
if (count % 2 === 0) {
const cycle = timer.cycle + 1;
setTimer({ ...timer, count, cycle });
return;
}
setTimer({ ...timer, count });
}, 1000);
}, [timer]);
return (
<div>
<br />
<br />
<br />
<br /> Playground:
<div>Count: {timer.count}</div>
<div>Cycle: {timer.cycle}</div>
<button type="button" onClick={(): void => setTrigger(trigger + 1)}>
Trigger Count: {trigger}
</button>
</div>
);
};
export default Component;
正如我所说,我有上述两个问题。我可以完全删除useEffect来解决双重渲染问题,但是当我单击“触发”按钮时,刻度会堆积起来,这比双重渲染还差。
评论的useRef部分是我尝试过的部分,但不起作用。
感谢所有帮助!
编辑: 第三个小问题是,这样的计数器仅以setTimeout运行,这将触发另一个setTimeout,因此,如果该过程花费一些时间,则实际上不是确切的间隔。
所以我的目标是在一个单独的进程中运行一个间隔(我会在useEffect中运行),这将导致在每个刻度上重新渲染,并且不会在每次调用时或在其他情况触发重新渲染时叠加。 / p>
答案 0 :(得分:0)
您可以修复#1中提到的内存泄漏。
React.useEffect(() => {
console.log("effect tick", timer);
// .. ? get the timeout ID to clear on unmount
const id = setTimeout(() => {
console.log(`tick id=${id}`, timer);
const count = timer.count + 1;
if (count % 2 === 0) {
const cycle = timer.cycle + 1;
setTimer({ ...timer, count, cycle });
return;
}
setTimer({ ...timer, count });
}, 1000);
// ... ? Clean up here with the ID on unmount
return () => clearTimeout(id);
}, [timer]);
关于#2双重渲染,您会更具体吗?
在上面useEffect
中进行清理之前/之后,由于当前的控制台日志似乎按预期工作,我无法弄清您的意思。