我面临一个奇怪的问题。
我有一个FCM Token
组件,其中包含以下代码:
Users
即使我清除了useEffect的返回函数中的间隔,我也在控制台中收到了此消息(指向notification
组件):
Family member User
返回Message
而不是const Message = (props) => {
const [timeout, setTimerTimeout] = useState(null);
const [someVar, setSomeVar] = useState(null);
useEffect(() => {
setTimerTimeout(prevTimeout => {
if (prevTimeout) {
clearInterval(prevTimeout);
}
return setInterval(someFunc, 1000)
});
}, [someVar]);
useEffect(() => {
return () => {
clearInterval(timeout);
};
}, []);
...
}
时,警告消失了(但是这当然不是我想要的,我只是知道间隔导致了问题)。
我不知道我在做什么错以及如何消除它。
有什么主意吗?谢谢!
答案 0 :(得分:2)
您的第二个useEffect仅在组件首次渲染时创建一次,因此它对timeout
的值为null。因此它将清除null。
尽管您不需要两种效果,而只需要一种。您可以修改第一个效果以包括一个拆解功能,而无需保存计时器ID来声明:
useEffect(() => {
let id = setInterval(someFunc, 1000);
return () => clearInterval(id);
}, [someVar]);
答案 1 :(得分:1)
如果组件在返回之前就已卸载,则可以使用保护变量来取消异步操作(在这种情况下为计时器,在其他情况下为获取请求)。
const Message = (props) => {
const [startInterval, setStartInterval] = useState(null);
useEffect(() => {
let cancel = false;
const intervalID = setInterval(() => { // run every second
if (!cancel) { // but don't run if component unmounts
someFunc();
}
}, 1000);
return () => { // runs when component unmounts
cancel = true; // stop an already-running interval
clearInterval(intervalID); // stop the interval generator
});
}, [startInterval]);
...
}
如果您使用setSomeVar
来允许用户手动停止计时器(例如发生点击事件)
const Message = (props) => {
const [startInterval, setStartInterval] = useState(null);
const [stopInterval, setStopInterval] = useState(null);
useEffect(() => {
let cancel = false;
let intervalID;
if (stopInterval && intervalID) {
clearInterval(intervalID); // manually stop the interval generator
} else {
intervalID = setInterval(() => { // run every second
if (!cancel) { // but don't run if component unmounts
someFunc();
}
}, 1000);
}
return () => { // runs when component unmounts
cancel = true; // stop an already-running interval
clearInterval(intervalID); // stop the interval generator
});
}, [startInterval, stopInterval]);
...
}
答案 2 :(得分:0)
useEffect
钩子的清理功能应该是建立效果的同一调用的一部分。
尝试一下:
useEffect(() => {
() => setTimerTimeout(prevTimeout => {
if (prevTimeout) {
clearInterval(prevTimeout);
}
return setInterval(someFunc, 1000)
});
return () => clearInterval(timeout);
}, [someVar]);
https://reactjs.org/docs/hooks-effect.html#effects-with-cleanup