我试着理解我的错误是什么。我在useEffect
中使用setInterval
,[]
依赖项更新ms
(毫秒)状态,每10毫秒加1。我有一个time()
函数,负责更新ms
和secs
状态,还负责停止和显示计时器。计时器达到5秒后,done
状态设置为true
,间隔被清除,计时器应停止,但它却崩溃并显示以下错误:“* 重新呈现太多。React限制呈现次数以防止无限循环 *"。为什么会发生这种情况?如何解决?以下是代码链接https://codepen.io/Montinyek/pen/zYLzBZP?editors=1111
function App() {
const [secs, setSecs] = React.useState(0);
const [ms, setMs] = React.useState(0);
const [done, setDone] = React.useState(false)
let id = React.useRef()
React.useEffect(() => {
id.current = setInterval(() => {
if (!done) {
setMs(prev => prev += 1)
}
}, 10);
return () => clearInterval(id.current);
}, [])
function time() {
if (ms === 100) {
setMs(0)
setSecs(prev => prev += 1)
}
if (secs === 5) {
clearInterval(id.current)
setDone(true)
}
let formattedSecs = secs < 10 ? "0" + secs : secs;
let formattedMils = ms < 10 ? "0" + ms : ms;
return `${formattedSecs} : ${formattedMils}`;
}
return <div>{time()}</div>;
}
1条答案
按热度按时间waxmsbnn1#
问题是你在 render 中调用了函数
time()
,而这个函数正在调用set state。通常,你不应该在render中设置state,或者你在渲染时进入了循环状态,状态被设置(这会触发重新渲染),然后状态被再次设置,然后重新渲染,依此类推。你的问题实际上并不在于新的时间间隔被创建了。它实际上在某种程度上与计时器的滴答声完全无关。问题是当它达到5秒时,它进入了一个“渲染循环”。
具体来说,你的情况是这样的:
1.计时器达到5秒。
1.渲染调用
time()
clearInterval(id.current)
被调用,setDone(true)
也被调用。这里的set操作导致另一个呈现。1.渲染调用
time()
。1.回到(3)。
您需要将设置状态的逻辑封装在间隔处理程序中,而不是使您的逻辑与渲染过程内在地链接。(在一个时间间隔内处理状态),因为在调用过时状态时会遇到各种各样的问题。你需要阅读DanAbramov(React的一个关键贡献者)的article about this,我已经从他的博客中删除了
useInterval
。请注意,渲染现在只调用不涉及状态的
getFormattedTime
。重构时,我发现不需要
done
,因为useInterval
支持通过传递一个变量tickrate来有条件地轻松停止间隔:secs < 5 ? 10 : null
.null
表示“已停止”。