React this.setState方法使用原理分析介紹
摘要
這一篇文章,主要是簡單的實(shí)現(xiàn)一下this.setState方法,為了實(shí)現(xiàn)該方法,就要知道this.setState方法具有什么特點(diǎn)。
首先在React組件中,我們先定義一個(gè)state和setState方法:
myState = { value: 0 } mySetState = ( changeState ) =>{ this.setState( this.myState ) }
這里可能會說,為什么在自己寫的mySetState 方法里還要調(diào)用React的setState呢?都調(diào)用人家的了還算自己寫的嗎?
由于在React中,render只能處理通過setState方法修改的值,所以這里我們在mySetState 中調(diào)用了一下。但是mySetState方法的具體實(shí)現(xiàn)還是我們自己去完成。
1.異步的setState
首先,我們看一段代碼:
state = { value: 0 }
setTimeout(() => { console.log('SetTimeOut ---- '+this.state.value); }, 0); new Promise((resolve,reject) => { resolve(this.state.value) }) .then(res => { console.log('Promise ---- '+res); }) this.setState({ value: this.state.value+1 }) console.log(this.state.value);
這段代碼會輸出什么呢?
由這個(gè)結(jié)果我們可以知道上面的代碼執(zhí)行順序:
(1)console.log(this.state.value);
(2)Promise代碼
(3)setState方法
(4)setTimeOut方法
所以setState一定是一個(gè)異步的方法。
在實(shí)現(xiàn)的時(shí)候,要注意異步的問題。
2.多個(gè)setState方法
我們繼續(xù)看一段代碼:
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 }) this.setState({ value: this.state.value+1 }) setTimeout(() => { console.log(this.state.value); }, 0);
這段代碼輸出的會是1還是5呢?
答案是1,這是React為了效率所作的一個(gè)優(yōu)化。防止每次setState都會導(dǎo)致render重新渲染!
而如果我就想要這個(gè)效果,React也是提供了一個(gè)解決辦法,就是setState方法可以接受一個(gè)函數(shù)作為參數(shù):
this.setState( (preState) => { return { value: preState.value+1 } } ) this.setState( (preState) => { return { value: preState.value+1 } } ) this.setState( (preState) => { return { value: preState.value+1 } } ) this.setState( (preState) => { return { value: preState.value+1 } } ) setTimeout(() => { console.log(this.state.value); }, 0);
preState代表的是上一個(gè)state。
3.手動(dòng)實(shí)現(xiàn)mySetState
OK,有了上面對setState方法分了解,我們可以手動(dòng)的實(shí)現(xiàn)一下mySetState方法
首先解決就是調(diào)用多個(gè)setState方法的時(shí)候,所以我們不能每次調(diào)用mySetState方法都讓state值更新,也就是這么寫:
mySetState = ( changeState ) =>{ Object.assign(this.myState,changeState) this.setState( this.myState ) }
我們只需要知道最后一個(gè)changeState,所以這里我們維護(hù)一個(gè)隊(duì)列,用來保存所有的changeState,然后每次調(diào)用mySetState 方法的時(shí)候,將changeState放到隊(duì)列里面:
queue = [] mySetState = ( changeState ) =>{ Promise.resolve().then(()=>{ this.stateShift() }) this.queue.push(changeState) this.setState( this.myState ) }
重頭戲來了,我們已經(jīng)有了這個(gè)隊(duì)列,那我們是如何讓這個(gè)隊(duì)列的changeState 出來的呢?
這里我們寫一個(gè)方法:
stateShift() { let empty; while(empty = this.queue.shift()){ } }
通過迭代器的方式,遍歷隊(duì)列。empty就是拿到的每個(gè)changeState 。changeState 有兩種形式,對象的時(shí)候肯定是很好寫的。
stateShift() { let empty; while(empty = this.queue.shift()){ if(typeof empty === 'object'){ Object.assign(this.myState,empty) } }
只需要讓新出來的去替換舊的就可以了。如果changeState 是一個(gè)方法,這個(gè)時(shí)候,我們需要手動(dòng)去維護(hù)一個(gè)preState變量,這個(gè)變量的作用就是用來保存上一個(gè)state。
所以具體的實(shí)現(xiàn)應(yīng)該為:
stateShift() { let empty; while(empty = this.queue.shift()){ if(!this.preState){ this.preState = Object.assign({},this.myState) } if(typeof empty === 'object'){ Object.assign(this.myState,empty) }else if(typeof empty === 'function'){ Object.assign(this.myState,empty(this.preState)) } this.preState = this.myState } }
最后一步,這個(gè)方法應(yīng)該什么時(shí)候調(diào)用。其實(shí)需要注意的無非就是,要在所有的changeState 都放到隊(duì)列中,再進(jìn)行調(diào)用。
而this.queue.push(changeState)這段代碼又是同步的代碼,所以在它之前,通過異步的方式調(diào)用,就可以實(shí)現(xiàn)出這種效果:
mySetState = ( changeState ) =>{ Promise.resolve().then(()=>{ this.stateShift() }) this.queue.push(changeState) this.setState( this.myState ) }
最后將整個(gè)實(shí)現(xiàn)代碼附上:
import React, { Component } from 'react' export default class Child extends Component { state = { value: 0 } myState = { value: 0 } queue = [] mySetState = ( changeState ) =>{ Promise.resolve().then(()=>{ this.stateShift() }) this.queue.push(changeState) this.setState( this.myState ) } stateShift() { let empty; while(empty = this.queue.shift()){ if(!this.preState){ this.preState = Object.assign({},this.myState) } if(typeof empty === 'object'){ Object.assign(this.myState,empty) }else if(typeof empty === 'function'){ Object.assign(this.myState,empty(this.preState)) } this.preState = this.myState } } add = ()=>{ //測試代碼 // this.mySetState( (pre) => { // return { // value: pre.value + 1 // } // } ) // this.mySetState( (pre) => { // return { // value: pre.value + 1 // } // } ) // this.mySetState( (pre) => { // return { // value: pre.value + 1 // } // } ) // this.mySetState({ // value: this.myState.value+1 // }) // this.mySetState({ // value: this.myState.value+1 // }) // this.mySetState({ // value: this.myState.value+1 // }) // this.mySetState({ // value: this.myState.value+1 // }) setTimeout(() => { console.log('SetTimeOut ---- '+this.myState.value); }, 0); new Promise((resolve,reject) => { resolve(this.myState.value) }) .then(res => { console.log('Promise ---- '+res); }) this.mySetState({ value: this.myState.value+1 }) console.log(this.myState.value); } render() { return ( <div> <span>{this.myState.value}</span> <br></br> <button onClick={this.add}>++</button> </div> ) } }
最后值得注意的是,這里只是針對于setState的一些特點(diǎn)去模擬了一下setState的實(shí)現(xiàn),具體的源碼可能不會像這樣簡單!
到此這篇關(guān)于React this.setState方法使用原理分析介紹的文章就介紹到這了,更多相關(guān)React this.setState內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
React系列useSyncExternalStore學(xué)習(xí)詳解
這篇文章主要為大家介紹了React系列useSyncExternalStore的學(xué)習(xí)及示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-07-07React實(shí)現(xiàn)頁面狀態(tài)緩存(keep-alive)的示例代碼
因?yàn)?react、vue都是單頁面應(yīng)用,路由跳轉(zhuǎn)時(shí),就會銷毀上一個(gè)頁面的組件,但是有些項(xiàng)目不想被銷毀,想保存狀態(tài),本文給大家介紹了React實(shí)現(xiàn)頁面狀態(tài)緩存(keep-alive)的代碼示例,需要的朋友可以參考下2024-01-01react項(xiàng)目引入antd框架方式以及遇到的一些坑
這篇文章主要介紹了react項(xiàng)目引入antd框架方式以及遇到的一些坑,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-03-03React報(bào)錯(cuò)Too many re-renders解決
這篇文章主要為大家介紹了React報(bào)錯(cuò)Too many re-renders解決,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12react中實(shí)現(xiàn)搜索結(jié)果中關(guān)鍵詞高亮顯示
這篇文章主要介紹了react中實(shí)現(xiàn)搜索結(jié)果中關(guān)鍵詞高亮顯示,使用react實(shí)現(xiàn)要比js簡單很多,方法都是大同小異,具體實(shí)現(xiàn)代碼大家跟隨腳本之家小編一起看看吧2018-07-07React父組件調(diào)用子組件中的方法實(shí)例詳解
最近做一個(gè)React項(xiàng)目,所有組件都使用了函數(shù)式組件,遇到一個(gè)父組件調(diào)用子組件方法的問題,下面這篇文章主要給大家介紹了關(guān)于React父組件調(diào)用子組件中方法的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-07-07