问题
写一个setInterval定时器实现数字的自增,因为之前做vue开发比较多,所以按照正常的思路写了一个发现count并不会每秒自增,而是只自增一次
const [count, setCount] = useState(0) useEffect(() => { const timer = setInterval(() => { setCount(count + 1) }, 1000) return () => clearInterval(timer) }, [])
后面发现useEffect的第二参数传入的是一个依赖list,若传入空数组则说明任何依赖的变化都不会导致useEffect重新执行,相当于类组件里面的componentDidMount生命周期只会执行一次,count的数值一直是初始化加载是闭包的count,所以count永远是0,界面上也只会显示1。
方案一:添加依赖
既然说第二个参数加入了依赖,只要这个依赖更新,useEffect就会再次执行,那么就在第二个参数里面加上count试试,定时器更新count,导致useEffect更新,count就可以获取到最新的值了。
const [count, setCount] = useState(0) useEffect(() => { const timer = setInterval(() => { setCount(count + 1) }, 1000) return () => clearInterval(timer) }, [count])
界面上的count果然更新了,说明这种方式确实有效。
方案二:函数更新
在类组件里面大家都知道setState在React处理机制下是异步执行的,但是里面传入一个函数可以获取到最新的值,所以Hooks里面是不是也有这样的机制,可以试试
const [count, setCount] = useState(0) useEffect(() => { const timer = setInterval(() => { setCount(v => v + 1) }, 1000) return () => clearInterval(timer) }, [])
结果发现界面上的数字count会随着时间自增。
方案三:使用useRef
useRef返回一个可变的ref对象,返回的ref对象在组件的整个生命周期内保持不变。 将定时器函数提取出来,每次定时器触发时,都能取到最新到count
const intervalRef = useRef(null) intervalRef.current = function () { setCount(count + 1) } useEffect(() => { const timer = setInterval(() => { intervalRef.current() }, 1000) return () => clearInterval(timer) }, [])
这里为什么成功呢,是因为React在组件重新渲染后整个生命周期都会执行一次,我们在大的生命周期中定义了intervalRef.current,所以这个intervalRef.current也会一直更新,所以里面获取到的count是最新的。
请登录后查看评论内容