V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
estk
V2EX  ›  React

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

  •  
  •   estk · 2022-10-23 11:57:00 +08:00 · 2862 次点击
    这是一个创建于 789 天前的主题,其中的信息可能已经有所发展或是发生改变。

    如下,增加一个 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 。
    sjhhjx0122
        15
    sjhhjx0122  
       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   ·   实用小工具   ·   1054 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 19:20 · PVG 03:20 · LAX 11:20 · JFK 14:20
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.