最近一直在學習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值。