setInterval 等读取不到 useState 最新值的问题你们怎么解决? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
estk
V2EX    React

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

  •  
  •   estk 3298 次点击
    这是一个创建于 1083 天前的主题,其中的信息可能已经有所发展或是发生改变。

    如下,增加一个 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 
    第 1 条附言    2022-10-23 18:26:00 +08:00
    按照 5 楼 @joesonw 的方式解决了,这个貌似最简洁
    16 条回复    2023-03-03 09:34:14 +08:00
    headsteins
        1
    headsteins  
       2022-10-23 12:01:12 +08:00
    使用 useRef 获取 state 的最新值吗?猜测可以用 ref.current = state 这样应该
    estk
        2
    estk  
    OP
       2022-10-23 12:45:56 +08:00
    @headsteins #1
    也有考虑过 useRef ,感觉这样跟多个全局变量差别不大
    kkocdko
        3
    kkocdko  
       2022-10-23 13:04:56 +08:00
    因为 hook 每次渲染都重新执行一遍,所以获取的是之前的闭包的值。useRef 是解决此类问题的惯用法。
    cutpictureboyxx
        4
    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
        5
    joesonw  
       2022-10-23 13:11:21 +08:00 via iPhone   1
    useEffect 也得 watch timeDate
    estk
        6
    estk  
    OP
       2022-10-23 13:26:30 +08:00
    @joesonw #5
    solved, thanx
    ragnaroks
        7
    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
        8
    ragnaroks  
       2022-10-23 13:28:04 +08:00
    setTimeDate((prev)=>console.log(prev))
    修正为:
    setTimeDate(function(prev){
    console.log(prev);
    return prev;
    })
    TWorldIsNButThis
        9
    TWorldIsNButThis  
       2022-10-23 13:31:31 +08:00
    @estk 这是 anti-pattern 因为每次重新渲染都清除了上一个 interval 创建了一个新的 interval
    TWorldIsNButThis
        10
    TWorldIsNButThis  
       2022-10-23 13:37:37 +08:00
    @estk
    这个问题的本质是闭包捕获了一个变量,但是由于每次重新渲染都生成了新的变量,因此导致捕获的变量其实只有这个闭包在使用它
    正确的做法就是让闭包捕获一个不变的引用,然后每次值变化同步修改引用的值,也就是 useRef
    darkengine
        11
    darkengine  
       2022-10-23 15:59:20 +08:00
    https://devtrium.com/posts/set-interval-react

    项目里用到的时候看了这篇,有码也有讲解。
    dcsuibian
        12
    dcsuibian  
       2022-10-23 16:14:05 +08:00
    react hooks 闭包陷阱
    oppddd
        13
    oppddd  
       2022-10-23 16:32:49 +08:00
    @estk 这个组件如果 第二次使用就会出问题
    hzxxx
        14
    hzxxx  
       2022-10-23 23:55:24 +08:00
    我觉得这逻辑不太对,你认同的解决方式,它只是获取到最新的 timeDate ,但是 setInterval 是最后一次更新 timeDate 之后的 2s 执行,但是你代码表达的就是不管 timeDate 更新多少次,我只要组件挂载了,就要在挂载的 setInterval2s 后获取到最新的 timeDate 。
    linkopeneyes
        15
    linkopeneyes  
       2022-10-24 15:29:43 +08:00
    react 实在太累了,如果有的选我宁愿 solidjs
    realJamespond
        16
    realJamespond  
       2023-03-03 09:34:14 +08:00
    回调里
    ```
    setTimeDate(prev=>prev)
    prev 就是最新值
    ```
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     3688 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 25ms UTC 10:20 PVG 18:20 LAX 03:20 JFK 06:20
    Do have faith in what you're doing.
    ubao snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86