React关于setState

故事:

最近一直在学习react,感受setState 在各篇文章中出现的几率仍是挺高的,所以学习记录下来关于setState的知识,以达到对react的认识
javascript

场景一 合成事件

constructor() {
    super()
    this.state = {
        value: 0
    }
}
handleClick() {
    this.setState({
        value: this.state.value + 1
    })
    this.setState({
        value: this.state.value + 1
    })
    this.setState({
        value: this.state.value + 1
    })
    this.setState({
        value: this.state.value + 1
    })
    console.log(this.state.value)
}
render() {
    return (
        <div className="part-main"> <button onClick={() => this.handleClick()}>{this.state.value}</button> </div>
    )
}复制代码

初始化的时候的时候 按钮显示0,点击按钮调用handleClick 输出0 按钮显示1
java

问题1:为何输出的不是4呢react

直观上调用handleClick时候 value被增长了3次,可是实际上却被增长了1次
实际上react为了解决跨平台,兼容性问题,本身封装了一套事件机制,代理了原生的事件,像在jsx中常见的onClick、onChange这些都是合成事件。setState在执行过程当中是一个很复杂的过程,由 React 控制的事件处理过程 setState 不会同步更新 this.state!,其实归根到底仍是为了提高性能,不管你setState执行了多少次,我只渲染一次,这样能够尽量的提高性能

别人是这样说的,我只是搬运工,方便本身看看数组

setState 后将传入的 state 放入队列 queue,enqueueUpdate 方法会根据 isBatchingUpdate 标志位判断,若当前已经在更新组件则将直接当前组件放入 dirtyComponents 数组,不然将 isBatchingUpdate 置为 true 并开启一个 "批量更新 (batchedUpdates)" 的事务(transaction)。


场景二 生命周期

constructor() {
    super()
    this.state = {
        value: 0
    }
}
componentDidMount() {
    this.setState({
        value: this.state.value + 1
    })
    this.setState({
        value: this.state.value + 1
    })
    this.setState({
        value: this.state.value + 1
    })
    console.log(this.state.value)
    //0 输出的仍是以前值
}
handleClick() {
    this.setState({
        value: this.state.value + 1
    })
    this.setState({
        value: this.state.value + 1
    })
    this.setState({
        value: this.state.value + 1
    })
    this.setState({
        value: this.state.value + 1
    })
    console.log(this.state.value)

}
render() {
    return (
        <div className="part-main">
            <button onClick={() => this.handleClick()}>{this.state.value}</button>
        </div>
    )
}复制代码

初始化的时候的时候 按钮显示1,componentDidMount阶段输出0,点击按钮调用handleClick 输出1 按钮显示2bash

其实仍是和合成事件同样,当componentDidmount执行的时候,react内部并无更新,执行完componentDidmount后才去commitUpdateQueue更新。这就致使你在componentDidmount中setState完去console.log拿的结果仍是更新前的值


场景三 原生事件

constructor() {
    super()
    this.state = {
        value: 0
    }
}
componentDidMount() {
    document.body.addEventListener('click', this.handleClick, false)
}
handleClick = () => {
    this.setState({
        value: this.state.value + 1
    })
    this.setState({
        value: this.state.value + 1
    })
    this.setState({
        value: this.state.value + 1
    })
    this.setState({
        value: this.state.value + 1
    })
    console.log(this.state.value)
}
render() {
    return (
        <div className="part-main">
            <button>{this.state.value}</button>
        </div>
    )
}复制代码

触发事件handleClick 输出4 按钮显示4,卧槽 为啥会这样?函数

原生事件是指非react合成事件,原生自带的事件监听 addEventListener ,或者也能够用原生js、jq直接 document.querySelector().onclick 这种绑定事件的形式都属于原生事件。  
原生事件中setState的调用栈就比较简单了,由于没有走合成事件的那一大堆,直接触发click事件,到requestWork ,在 requestWork 里因为 expirationTime === Sync 的缘由,直接走了 performSyncWork 去更新,并不像合成事件或钩子函数中被return,因此当你在原生事件中setState后,能同步拿到更新后的state值。

场景4 setTimeout

constructor() {
    super()
    this.state = {
        value: 0
    }
}
componentDidMount() {
   setTimeout(() => {
       this.setState({
           value: this.state.value + 1
       })
       this.setState({
           value: this.state.value + 1
       })
       this.setState({
           value: this.state.value + 1
       })
       this.setState({
           value: this.state.value + 1
       })
       console.log(this.state.value)
   },0)
}
handleClick = () => {

}
render() {
    return (
        <div className="part-main">
            <button>{this.state.value}</button>
        </div>
    )
}复制代码

setTimeout后 输出4 按钮显示4,卧槽 为啥又是4?
oop

在 setTimeout 中去 setState 并不算是一个单独的场景,它是随着你外层去决定的,由于你能够在合成事件中 setTimeout,能够在钩子函数中 setTimeout,也能够在原生事件setTimeout,可是无论是哪一个场景下,基于event loop的模型下,setTimeout 中里去 setState 总能拿到最新的state值。
相关文章
相关标签/搜索