setInterval 等读取不到 useState 最新值的问题你们怎么解决?

2022-10-23 11:57:00 +08:00
 estk

如下,增加一个 timeDateG 不是最优雅的方式吧?

import { useEffect, useState } from "react"
let timeDateG = '00:00:00'
const UseStateIssue = () => {
  const [timeDate, setTimeDate] = useState('00:00:00')
  useEffect(()=>{
    timeDateG = timeDate
  }, [timeDate])
  useEffect(()=>{
    const interval = setInterval(()=>{
      console.log('timeDate', timeDate) // 一直是 '00:00:00'
      console.log('timeDateG', timeDateG) // 解决方法 1
    }, 2000)
    return () => clearInterval(interval)
  }, [])
  return (
    <div>
      <div>{timeDate},这里正常刷新</div>
      <button onClick={()=>{
        setTimeDate(new Date().toLocaleTimeString())
        }}>setTimeDate</button>
    </div>
  )
}
export default UseStateIssue
2862 次点击
所在节点    React
16 条回复
headsteins
2022-10-23 12:01:12 +08:00
使用 useRef 获取 state 的最新值吗?猜测可以用 ref.current = state 这样应该
estk
2022-10-23 12:45:56 +08:00
@headsteins #1
也有考虑过 useRef ,感觉这样跟多个全局变量差别不大
kkocdko
2022-10-23 13:04:56 +08:00
因为 hook 每次渲染都重新执行一遍,所以获取的是之前的闭包的值。useRef 是解决此类问题的惯用法。
cutpictureboyxx
2022-10-23 13:10:18 +08:00
useEffect(()=>{
const interval = setInterval(()=>{
console.log('timeDate', timeDate) // 一直是 '00:00:00'
console.log('timeDateG', timeDateG) // 解决方法 1
}, 2000)
return () => clearInterval(interval)
}, [timeDate, timeDateG])
joesonw
2022-10-23 13:11:21 +08:00
useEffect 也得 watch timeDate
estk
2022-10-23 13:26:30 +08:00
@joesonw #5
solved, thanx
ragnaroks
2022-10-23 13:26:59 +08:00
idiot:
const [timeDate, setTimeDate] = useState('00:00:00')

useEffect(()=>{
const interval = setInterval(()=>{
console.log(timeDate)
}, 2000)
return () => clearInterval(interval)
}, [timeDate])



kid:
const [timeDate, setTimeDate] = useState('00:00:00')
const ref1 = useRef(timeDate)

useEffect(()=>{
const interval = setInterval(()=>{
console.log(ref1.current)
}, 2000)
return () => clearInterval(interval)
}, [ref1])



legend:
const [timeDate, setTimeDate] = useState('00:00:00')

useEffect(()=>{
const interval = setInterval(()=>{
setTimeDate((prev)=>console.log(prev))
}, 2000)
return () => clearInterval(interval)
}, [setTimeDate])
ragnaroks
2022-10-23 13:28:04 +08:00
setTimeDate((prev)=>console.log(prev))
修正为:
setTimeDate(function(prev){
console.log(prev);
return prev;
})
TWorldIsNButThis
2022-10-23 13:31:31 +08:00
@estk 这是 anti-pattern 因为每次重新渲染都清除了上一个 interval 创建了一个新的 interval
TWorldIsNButThis
2022-10-23 13:37:37 +08:00
@estk
这个问题的本质是闭包捕获了一个变量,但是由于每次重新渲染都生成了新的变量,因此导致捕获的变量其实只有这个闭包在使用它
正确的做法就是让闭包捕获一个不变的引用,然后每次值变化同步修改引用的值,也就是 useRef
darkengine
2022-10-23 15:59:20 +08:00
https://devtrium.com/posts/set-interval-react

项目里用到的时候看了这篇,有码也有讲解。
dcsuibian
2022-10-23 16:14:05 +08:00
react hooks 闭包陷阱
oppddd
2022-10-23 16:32:49 +08:00
@estk 这个组件如果 第二次使用就会出问题
hzxxx
2022-10-23 23:55:24 +08:00
我觉得这逻辑不太对,你认同的解决方式,它只是获取到最新的 timeDate ,但是 setInterval 是最后一次更新 timeDate 之后的 2s 执行,但是你代码表达的就是不管 timeDate 更新多少次,我只要组件挂载了,就要在挂载的 setInterval2s 后获取到最新的 timeDate 。
sjhhjx0122
2022-10-24 15:29:43 +08:00
react 实在太累了,如果有的选我宁愿 solidjs
realJamespond
2023-03-03 09:34:14 +08:00
回调里
```
setTimeDate(prev=>prev)
prev 就是最新值
```

这是一个专为移动设备优化的页面(即为了让你能够在 Google 搜索结果里秒开这个页面),如果你希望参与 V2EX 社区的讨论,你可以继续到 V2EX 上打开本讨论主题的完整版本。

https://www.v2ex.com/t/889077

V2EX 是创意工作者们的社区,是一个分享自己正在做的有趣事物、交流想法,可以遇见新朋友甚至新机会的地方。

V2EX is a community of developers, designers and creative people.

© 2021 V2EX