javascript - 使用 useEffect 中的旧状态反应间隔
问题描述
我遇到了一种情况,我从 useEffect 内部设置了一个间隔计时器。我可以访问 useEffect 中的组件变量和状态,并且间隔计时器按预期运行。但是,计时器回调无权访问组件变量/状态。通常,我希望这是“this”的问题。但是,我不相信“这个”是这里的情况。没有双关语。我在下面包含了一个简单的示例:
import React, { useEffect, useState } from 'react';
const App = () => {
const [count, setCount] = useState(0);
const [intervalSet, setIntervalSet] = useState(false);
useEffect(() => {
if (!intervalSet) {
setInterval(() => {
console.log(`count=${count}`);
setCount(count + 1);
}, 1000);
setIntervalSet(true);
}
}, [count, intervalSet]);
return <div></div>;
};
export default App;
控制台每秒仅输出 count=0 。我知道有一种方法可以将函数传递给 setCount 来更新当前状态,并且在这个简单的示例中有效。然而,这不是我想要表达的意思。真正的代码比我在这里展示的要复杂得多。我的真实代码查看由异步 thunk 操作管理的当前状态对象。另外,我知道我没有包含组件卸载时的清理功能。对于这个简单的示例,我不需要它。
解决方案
第一次运行时useEffect
,intervalSet
变量设置为true
,间隔函数是使用当前值 (0) 创建的。
在随后的运行中,useEffect
由于检查,它不会重新创建间隔,intervalSet
并继续运行现有的间隔,其中 count 是原始值 (0)。
你让这变得比它需要的更复杂。
useState
set 函数可以接受一个传递状态当前值并返回新值的函数,即setCount(currentValue => newValue);
卸载组件时应始终清除间隔,否则当它尝试设置状态并且状态不再存在时,您将遇到问题。
import React, { useEffect, useState } from 'react';
const App = () => {
// State to hold count.
const [count, setCount] = useState(0);
// Use effect to create and clean up the interval
// (should only run once with current dependencies)
useEffect(() => {
// Create interval get the interval ID so it can be cleared later.
const intervalId = setInterval(() => {
// use the function based set state to avoid needing count as a dependency in the useEffect.
// this stops the need to code logic around stoping and recreating the interval.
setCount(currentCount => {
console.log(`count=${currentCount}`);
return currentCount + 1;
});
}, 1000);
// Create function to clean up the interval when the component unmounts.
return () => {
if (intervalId) {
clearInterval(intervalId);
}
}
}, [setCount]);
return <div></div>;
};
export default App;
您可以运行代码并在下面看到它的工作原理。
const App = () => {
// State to hold count.
const [count, setCount] = React.useState(0);
// Use effect to create and clean up the interval
// (should only run once with current dependencies)
React.useEffect(() => {
// Create interval get the interval ID so it can be cleared later.
const intervalId = setInterval(() => {
// use the function based set state to avoid needing count as a dependency in the useEffect.
// this stops the need to code logic around stoping and recreating the interval.
setCount(currentCount => {
console.log(`count=${currentCount}`);
return currentCount + 1;
});
}, 1000);
// Create function to clean up the interval when the component unmounts.
return () => {
if (intervalId) {
clearInterval(intervalId);
}
}
}, [setCount]);
return <div></div>;
};
ReactDOM.render(<App />, document.getElementById('app'))
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/17.0.1/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/17.0.1/umd/react-dom.production.min.js"></script>
<div id="app"></div>
推荐阅读
- ios - 使用单独的控制器将自定义单元格中的标签设置为数组中的名称
- c - 能够从尚未分配值的malloc'ed范围中读取它是一个安全漏洞吗?
- swiftui - 当按钮靠在一起时,SwiftUI NavigationLink 行为不正确
- python - Allennlp 德国 elmo 模型
- substrate - 如何实现以太坊虚拟机托盘?
- python-3.x - 如何在 Python 中的 Pandas Dataframe 中将 123456.654321 更改为 12:34:56:654321
- reactjs - 如何在 ReactJS 中获取当前路径
- c# - WebApi 返回 json 与返回 OK(json)
- css - css3变换比例的RangeSlider问题
- excel - 下载C盘文件名到指定文件夹