【发布时间】:2019-12-13 04:13:03
【问题描述】:
我正在尝试了解新的 React 钩子及其用例。
我的目标是增加一个计数的单个组件,并且每个 x 滴答计数另一个计数器。
我使用 useEffect 和 useState 实现了它,主要有两个问题:
1. 在调用超时之前卸载组件时的内存泄漏(使用 react-router 导航时)
2. 由于useEffect 和useState 都触发了渲染,因此组件在每个tick 上渲染两次。
我认为解决方案将是 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 中),这将导致每次滴答时重新渲染,并且不会在每次调用或其他触发重新渲染时叠加。
【问题讨论】:
-
对于清理,useEffect 应该返回一个删除计时器的函数(将在 unMount 上调用)。为此,您应该使用 useInterval 并将其保存在本地,这会得到清理:return () => clearTimeout(t),其中 t 是您的间隔/超时
标签: reactjs memory-leaks settimeout setinterval react-hooks