反应:在有效的时间间隔内缺少依赖警告
Posted
技术标签:
【中文标题】反应:在有效的时间间隔内缺少依赖警告【英文标题】:React: missing dependency warning within interval in effect 【发布时间】:2021-10-03 17:29:38 【问题描述】:我有一个用 React 和 Next.js 构建的反应页面,看起来像这样。
import Head from 'next/head';
import useEffect, useState from 'react';
import Header from '../components/Header';
export default function Home()
const ticksPerSecond = 10;
const [points, setPoints] = useState(10);
const [pointsPerSecond, setPointsPerSecond] = useState(2);
useEffect(() =>
setInterval(() =>
setPoints((points) => points + pointsPerSecond / ticksPerSecond);
, 1000 / ticksPerSecond);
, []);
return (
<>
<Header points=points pointsPerSecond=pointsPerSecond />
</>
);
此代码按预期工作。每秒points
将增加pointsPerSecond
,状态将每秒更新10 次(由ticksPerSecond
确定)。
我的问题来自 eslint,它警告我:
React Hook useEffect has a missing dependency: 'pointsPerSecond'. Either include it or remove the dependency array. You can also replace multiple useState variables with useReducer if 'setPoints' needs the current value of 'pointsPerSecond'.eslintreact-hooks/exhaustive-deps
阅读该警告后,我尝试了许多不同的解决方案来安抚天空中的 eslint 众神,但我能做到的最好是用不同的警告替换警告。具体来说,我已经尝试了来自this question 的解决方案,看起来同样的问题。但是,这些解决方案都没有抑制警告。
【问题讨论】:
pointsPerSecond
是否会在某个时候发生变化?为什么它是有状态的?
@Nick 是的,它将作为应用程序使用的一部分进行更改。尚未实施
ticksPerSecond
永远不会改变吗?
@Nick ticksPerSecond 是常数。
【参考方案1】:
尝试在依赖数组上添加 pointsPerSecond
useEffect(() =>
setInterval(() =>
setPoints((points) => points + pointsPerSecond / ticksPerSecond);
, 1000 / ticksPerSecond);
, [pointsPerSecond]);
或者你可以忽略警告使用 // eslint-disable-next-line react-hooks/exhaustive-deps
useEffect(() =>
setInterval(() =>
setPoints((points) => points + pointsPerSecond / ticksPerSecond);
, 1000 / ticksPerSecond);
// eslint-disable-next-line react-hooks/exhaustive-deps
, []);
【讨论】:
当pointsPerSecond改变时,这不会开始另一个间隔吗? 在这种情况下,您可以使用 // eslint-disable-next-line react-hooks/exhaustive-deps 来禁用警告【参考方案2】:我建议将pointsPerSecond
添加到依赖数组中,然后确保从效果中返回一个清理函数,以清除现有间隔。这假设您想要停止任何现有间隔并在pointsPerSecond
更改时开始一个新间隔。如果您没有在依赖项数组中包含 pointsPerSecond
,那么您将使用该依赖项的陈旧版本。
import Head from 'next/head';
import useEffect, useState from 'react';
import Header from '../components/Header';
const ticksPerSecond = 10;
export default function Home()
const [points, setPoints] = useState(10);
const [pointsPerSecond, setPointsPerSecond] = useState(2);
useEffect(() =>
const interval = setInterval(() =>
setPoints((points) => points + pointsPerSecond / ticksPerSecond);
, 1000 / ticksPerSecond);
return () => clearInterval(interval)
, [pointsPerSecond]);
return (
<>
<Header points=points pointsPerSecond=pointsPerSecond />
</>
);
有几个原因我几乎总是建议不要为钩子依赖数组消除 linting 错误:
您几乎总是希望您的钩子具有最新的值。 如果您将依赖项数组的 lint 警告设为静音,那么您将不会收到有关 future 依赖项的警告,而您可能确实希望收到警告。【讨论】:
因为 pointsPerSecond 可以改变,这不会导致两个区间同时运行吗? 没有。useEffect
钩子返回的清理函数清除之前的区间【参考方案3】:
我会做一些改变。
-
不要忘记在 unmouted 上清除 Interval,
在调用 setState 之前进行挂载检查。
添加 esLint 警告您的依赖项。
下面是一个例子。
useEffect(() =>
let mounted = true;
const i = setInterval(() =>
if (mounted) setPoints((points) => points + pointsPerSecond / ticksPerSecond);
, 1000 / ticksPerSecond);
return () => clearInterval(i); mounted = false;
, [pointsPerSecond]);
【讨论】:
这很有趣,mounted
变量提供了清除间隔所没有的功能?
因为 pointsPerSecond 可以改变,这不会导致两个区间同时运行吗?
@JulianLachniet 不,这就是我们做 clearInterval 的原因。
@Nick 只是以防万一在卸载后间隔仍然触发,它通常不会导致问题,除了从 React 在控制台中收到关于在未安装的组件上调用 setState 的警告。对于像这样微不足道的事情,这可能不是问题,但是任何形式的异步代码我现在都只是做一个安装检查,我只是不喜欢控制台混乱。 :)。以上是关于反应:在有效的时间间隔内缺少依赖警告的主要内容,如果未能解决你的问题,请参考以下文章