阅读 731

React Hook与闭包

useState 反直觉异步更新问题

function UseStateDemo() {
    const [num,setNum] = useState(0)
    const addNumber = ()=>{
        setTimeout(()=>{
            setNum(()=> num + 1)
        },2000)
    }
    return {num}
}
复制代码

先说结论:setTimeout里访问的num是闭包里的变量,这在一开始函数执行后就被保存下来了,下一次state更新后,再次render是生成了一个新的函数作用域,所以在这里延时后setTimeout依然会使用旧值去更新。

事实上,这就是一个简单的闭包问题,我会在接下来的代码上试图论证我上面的说法。

function preserveNum(){
  let num = 0
  setTimeout(()=>{
    num++
  },1000)
  return function(){
    console.log(num)
  }
}

const printNum = preserveNum()

setTimeout(()=>{
  printNum() // 1
  const newPrintNum = preserveNum() //重新执行一次
  newPrintNum() //0
},2000)
复制代码

从这个demo上就很好理解了,新执行的preserveNum下,创建了一个新的内部作用域,当然与第一次执行返回的函数是毫无关联的了,这就能解通了。

你或许可以再试试下面的奇怪代码

function printAge() {
    const [state,setState] = useState(0)
    const Kent = {
        age: 0
    }
    const  add = ()=>{
        setTimeout(()=>{
            setState(Kent.age ++)
        })
    }
    return 
        {state + 'Kent的年龄是' + Kent.age}
    
}
复制代码

这些问题在诸如使用useMemouseCallback上也是常见的,他们会缓存一些值或函数,这并不是什么高深的东西,就是依靠闭包所完成的。

事实上React hook的抽象是在业务上很符合直觉的,这只取决于如何正确的使用他们。

本文如有错误的地方,欢迎指正和交流

文章分类
前端
文章标签