不合预期的更新
在定时器中,用useState使数字做每1秒递增1,但结果不合预期:数字增加一次后便不再改变
Counter.js
// Counter.js
import React, { useState } from 'react'
import './Counter.css'
function IntervalCounter() {
const [n, setN] = useState(0)
function autoIncrease() {
setInterval(() => {
setN(n + 1) // 只增加一次
}, 1000)
}
return (
{n}
autoIncrease()}>Set Interval To Increase
)
}
export default { IntervalCounter }
index.js
// index.js
import React from 'react'
import ReactDOM from 'react-dom'
import Counter from './Counter'
ReactDOM.render(
,
document.getElementById('root')
)
要弄清为什么setN(n + 1)没有生效,要先了解传入的参数值代表了什么含义。当我们传入n+1,是在告诉React,下一轮的渲染按照我给的值。因为n是一个变量,所以要确定下来这个变量到底是多少,即n指代的是哪一个。
下面两点很重要:
在函数式组件中,state和prop都是不可变的
函数取到的是本次渲染中内的变量n
看到的视图有两种状态,也就对应两个渲染状态:
上面两点的意思也就是:在渲染1内,n永远为;setN这个函数取到的n是0,设置n+1永远是1。
当我们第一次点击按钮时,触发的是渲染1中的函数,这个函数会每隔一秒执行一次setN,但每次参数都是0+1
如果想要将值置为2,需要触发渲染2中的函数才能做到。也就是当视图显示为1之后,再次去点击按钮。
由于定时器没有清理,可以看到数值在1和2间反复交替。
这也验证了渲染1的定时器只能将值置为1,渲染2的定时器只能将值置为2。
如何使更新符合更新
解决这个问题的方法很简单,即把**useState里面设置变量的方法里传入一个函数**即可
setN(n + 1)改写成setN(n => n + 1)
传入一个函数(setN(n => n + 1)),是在告诉React一个指令,下一轮的组件在之前的基础上加一。不用像值作为参数时,关心当前渲染状态下的值具体是多少。
最后
setN(n + 1)的这种写法并没有问题,如果不用定时器,而是手动点击触发递增,结果也是符合预期的
function SimpleCounter() {
const [n, setN] = useState(0)
function handleClick() {
setN(n + 1)
}
return (
{n}
handleClick()}>Click +1
)
}
三次点击触发的是三个渲染内的三个函数,每一个函数内setN的参数都是不同的。
小伙伴,你们有什么看法?请在下方留言哟。
领取专属 10元无门槛券
私享最新 技术干货