最近一直在学习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值。
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值。