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