我有一个函数react组件,该组件的计数器从10000开始到0。
我在组件安装期间使用useEffect钩子设置了setInterval回调。然后,回调将更新计数器状态。
但是我不知道为什么,count
的值永远不会减少。每次回调运行count
都是10000。
(我正在使用react&react-dom版本16.8.3
)
功能组件如下:
import React, { useState, useEffect, useRef } from 'react'
const Counter = () => {
const timerID = useRef()
let [count, setCount] = useState(10000)
useEffect(() => {
timerID.current = setInterval(() => {
//count here is always 10000
if (count - 1 < 0) {
setCount(0)
} else {
setCount(count - 1)
}
}, 1)
}, [])
return <h1 className="counter">{count}</h1>
}
export default Counter
以下是指向codeandbox的链接:link
答案 0 :(得分:3)
您需要注意count
中的更改,并清理useEffect()
:
useEffect(() => {
timerID.current = setInterval(() => {
if (count - 1 < 0) {
setCount(0)
} else {
setCount(count - 1)
}
}, 100)
return () => clearInterval(timerID.current);
}, [count])
如@Pavel所述,Dan Abramov解释了为什么here。
答案 1 :(得分:1)
您正在按照您所说的那样在安装组件时声明效果功能。因此,在该范围内,时间值存储内部计数等于10000。这意味着每个时间间隔函数执行都从闭包(10000)中获取计数值。正确地做到这一点实际上很难。丹(Dan)为此写了整本blog post
答案 2 :(得分:1)
有2个选项:
1)在依赖项中包含count
这并不理想,因为这意味着将在setInterval
的每次更改中创建一个新的count
,因此您需要在每次渲染时都将其清除,例如:
useEffect(() => {
timerID.current = setInterval(() => {
//count here is always 10000
if (count - 1 < 0) {
setCount(0)
} else {
setCount(count - 1)
}
}, 1)
return () => clearInterval(timerID.current) // Added this line
}, [count]) // Added count here
2)在count
回调函数中添加setInterval
。
这是间隔的最佳方法,因为它避免了始终设置新间隔的方法。
useEffect(() => {
timerID.current = setInterval(() => {
// count is used inside the setCount callback and has latest value
setCount(count => {
if (count - 1 < 0) { // Logic moved inside the function, so no dependencies
if (timerID.current) clearInterval(timerID.current)
return 0
}
return count - 1
})
}, 1)
return () => {
if (timerID.current) clearInterval(timerID.current) // Makes sure that the interval is cleared on change or unmount
}
}, [])
这里是sandbox link