如下,增加一个 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
headsteins 2022-10-23 12:01:12 +08:00
使用 useRef 获取 state 的最新值吗?猜测可以用 ref.current = state 这样应该
|
2
estk OP @headsteins #1
也有考虑过 useRef ,感觉这样跟多个全局变量差别不大 |
3
kkocdko 2022-10-23 13:04:56 +08:00
因为 hook 每次渲染都重新执行一遍,所以获取的是之前的闭包的值。useRef 是解决此类问题的惯用法。
|
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]) |
5
joesonw 2022-10-23 13:11:21 +08:00 via iPhone 1
useEffect 也得 watch timeDate
|
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]) |
8
ragnaroks 2022-10-23 13:28:04 +08:00
setTimeDate((prev)=>console.log(prev))
修正为: setTimeDate(function(prev){ console.log(prev); return prev; }) |
9
TWorldIsNButThis 2022-10-23 13:31:31 +08:00
@estk 这是 anti-pattern 因为每次重新渲染都清除了上一个 interval 创建了一个新的 interval
|
10
TWorldIsNButThis 2022-10-23 13:37:37 +08:00
@estk
这个问题的本质是闭包捕获了一个变量,但是由于每次重新渲染都生成了新的变量,因此导致捕获的变量其实只有这个闭包在使用它 正确的做法就是让闭包捕获一个不变的引用,然后每次值变化同步修改引用的值,也就是 useRef |
11
darkengine 2022-10-23 15:59:20 +08:00
|
12
dcsuibian 2022-10-23 16:14:05 +08:00
react hooks 闭包陷阱
|
14
hzxxx 2022-10-23 23:55:24 +08:00
我觉得这逻辑不太对,你认同的解决方式,它只是获取到最新的 timeDate ,但是 setInterval 是最后一次更新 timeDate 之后的 2s 执行,但是你代码表达的就是不管 timeDate 更新多少次,我只要组件挂载了,就要在挂载的 setInterval2s 后获取到最新的 timeDate 。
|
15
sjhhjx0122 2022-10-24 15:29:43 +08:00
react 实在太累了,如果有的选我宁愿 solidjs
|
16
realJamespond 2023-03-03 09:34:14 +08:00
回调里
``` setTimeDate(prev=>prev) prev 就是最新值 ``` |