问题
需求是每秒请求日志信息 如果连续5s不变则进行下一步
function Comp() {
const [log, setLog] = useState()
useEffect(() => {
let counter = 0
let timer
const cleanup = () => clearInterval(timer)
const fetchLog = () => {
getLog().then(newLog => {
if (log !== newLog) {
counter = 0
setLog(newLog)
return
}
++counter
if (counter >= 5) {
cleanup()
// 下一步操作
}
})
}
fetchLog()
timer = setInterval(fetchLog, 1000)
return cleanup
}, [])
return ...
}
实测的时候发现始终无法进行下一步 即使调整getLog函数的值始终一致
在适当的位置打印后 发现参与比较的log始终是undefined
此时我理解了bug的原因:useEffect始终调用了第一次接受的setup函数,而参与比较的log来自于该函数的闭包,它的值是不会更新的.
每次调用组件函数得到的state可能与上一次不同,这种不同构成了组件state的可变性,但每次调用组件函数取得的值本身是不会变的.这个还是挺容易出错了,需要自己小心
解决
使用回调函数作为setState的参数,该函数始终能得到最新的state;也可以用一个ref,每次setState时都为ref赋值
getLog().then(newLog => {
setLog(log=>{
if(log!==newLog)
//...
})
})