如下,增加一个 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 ![]() 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 linkopeneyes 2022-10-24 15:29:43 +08:00 react 实在太累了,如果有的选我宁愿 solidjs |
16 realJamespond 2023-03-03 09:34:14 +08:00 回调里 ``` setTimeDate(prev=>prev) prev 就是最新值 ``` |