日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

更合理的 setState()

發(fā)布時(shí)間:2025/3/20 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 更合理的 setState() 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

原文發(fā)表在我的博客:www.erichain.me/2017/04/17/…

React 是我做前端以來接觸到的第三個(gè)框架(前兩個(gè)分別是 Angular 和 Vue),無論是從開發(fā)體驗(yàn)上和效率上,這都是一門非常優(yōu)秀的框架,非常值得學(xué)習(xí)。

原諒我說了一些廢話,以下是正文。

借助于 Redux,我們可以輕松的對(duì) React 中的狀態(tài)進(jìn)行管理和維護(hù),同時(shí),React 也為我們提供了組件內(nèi)的狀態(tài)管理的方案,也就是 setState()。本文不會(huì)涉及到 Redux,我們將從 Component 的角度來說明你不知道的以及更合理的 setState()。

先說說大家都知道的

在 React 文檔的 State and Lifecycle 一章中,其實(shí)有明確的說明 setState() 的用法,向 setState() 中傳入一個(gè)對(duì)象來對(duì)已有的 state 進(jìn)行更新。

比如現(xiàn)在有下面的這樣一段代碼:

class MyComponent extends React.Component {constructor(props) {super(props);this.state = {count: this.state.count + 1};} }復(fù)制代碼

我們?nèi)绻胍獙?duì)這個(gè) state 進(jìn)行更新的話,就可以這樣使用 setState():

this.setState({count: 1 });復(fù)制代碼

你可能不知道的

最基本的用法世人皆知,但是,在 React 的文檔下面,還寫著,處理關(guān)于異步更新 state 的問題的時(shí)候,就不能簡(jiǎn)單地傳入對(duì)象來進(jìn)行更新了。這個(gè)時(shí)候,需要采用另外一種方式來對(duì) state 進(jìn)行更新。

setState() 不僅能夠接受一個(gè)對(duì)象作為參數(shù),還能夠接受一個(gè)函數(shù)作為參數(shù)。函數(shù)的參數(shù)即為 state 的前一個(gè)狀態(tài)以及 props。

所以,我們可以向下面這樣來更新 state:

this.setState((prevState, props) => ({ count: prevState.count + 1 }));復(fù)制代碼

這樣寫的話,能夠達(dá)到同樣的效果。那么,他們之間有什么區(qū)別呢?


區(qū)別

我們來詳細(xì)探討一下為什么會(huì)有兩種設(shè)置 state 的方案,他們之間有什么區(qū)別,我們應(yīng)該在何時(shí)使用何種方案來更新我們的 state 才是最好的。

此處,為了能夠明確的看出 state 的更新,我們采用一個(gè)比較簡(jiǎn)單的例子來進(jìn)行說明。

我們?cè)O(shè)置一個(gè)累加器,在 state 上設(shè)置一個(gè) count 屬性,同時(shí),為其增加一個(gè) increment 方法,通過這個(gè) increment 方法來更新 count。

此處,我們采用給 setState() 傳入對(duì)象的方式來更新 state,同時(shí),我們?cè)诖颂幵O(shè)置每調(diào)用一次 increment 方法的時(shí)候,就調(diào)用兩次 setState()。具體的原因我們?cè)诤笪闹袝?huì)講解。

具體的代碼如下:

class IncrementByObject extends React.Component {constructor(props) {super(props);this.state = {count: 0};this.increment = this.increment.bind(this);}// 此處設(shè)置調(diào)用兩次 setState()increment() {this.setState({count: this.state.count + 1});this.setState({count: this.state.count + 1});}render() {return (<div><button onClick={this.increment}>IncrementByObject</button><span>{this.state.count}</span></div>);} }ReactDOM.render(<IncrementByObject />,document.getElementById('root') );復(fù)制代碼

這時(shí)候,我們點(diǎn)擊 button 的時(shí)候,count 就會(huì)更新了。但是,可能與我們所預(yù)期的有所差別。我們?cè)O(shè)置了點(diǎn)擊一次就調(diào)用兩次 setState(),但是,count 每一次卻還是只增加了 1,所以這是為什么呢?

其實(shí),在 React 內(nèi)部,對(duì)于這種情況,采用的是對(duì)象合并的操作,就和我們所熟知的 Object.assign() 執(zhí)行的結(jié)果一樣。

比如,我們有以下的代碼:

Object.assign({}, { a: 2, b: 3 }, { a: 1, c: 4 });復(fù)制代碼

那么,我們最終得到的結(jié)果將會(huì)是 { a: 1, b: 3, c: 4 }。對(duì)象合并的操作,屬性值將會(huì)以最后設(shè)置的屬性的值為準(zhǔn),如果發(fā)現(xiàn)之前存在相同的屬性,那么,這個(gè)屬性將會(huì)被后設(shè)置的屬性所替換。所以,也就不難理解為什么我們調(diào)用了兩次 setState() 之后,count 依然只增加了 1 了。

用簡(jiǎn)短的代碼說明就是這樣:

this.setState({count: this.state.count + 1 });// 同理于 Object.assign({}, this.state, { count: this.state.count + 1 });復(fù)制代碼

以上是我們采用對(duì)象的方式傳入 setState() 來更新 state 的說明。接下來我們?cè)倏纯词褂煤瘮?shù)的方式來更新 state 會(huì)有怎么樣的效果呢?


我們將上面的累加器采用另外的方式來實(shí)現(xiàn)一次,在 setState() 的時(shí)候,我們采用傳入一個(gè)函數(shù)的方式來更新我們的 state。

class IncrementByFunction extends React.Component {constructor(props) {super(props);this.state = {count: 0};this.increment = this.increment.bind(this);}increment() {// 采用傳入函數(shù)的方式來更新 statethis.setState((prevState, props) => ({count: prevState.count + 1}));this.setState((prevState, props) => ({count: prevState.count + 1}));}render() {return (<div><button onClick={this.increment}>IncrementByFunction</button><span>{this.state.count}</span></div>);} }ReactDOM.render(<IncrementByFunction />,document.getElementById('root') );復(fù)制代碼

當(dāng)我們?cè)俅吸c(diǎn)擊按鈕的時(shí)候,就會(huì)發(fā)現(xiàn),我們的累加器就會(huì)每次增加 2 了。

我們可以通過查看 React 的源代碼來找出這兩種更新 state 的區(qū)別 (此處只展示通過傳入函數(shù)進(jìn)行更新的方式的部分源碼)。

在 React 的源代碼中,我們可以看到這樣一句代碼:

this.updater.enqueueSetState(this, partialState, callback, 'setState');復(fù)制代碼

然后,enqueueSetState 函數(shù)中又會(huì)有這樣的實(shí)現(xiàn):

queue.push(partialState); enqueueUpdate(internalInstance);復(fù)制代碼

所以,與傳入對(duì)象更新 state 的方式不同,我們傳入函數(shù)來更新 state 的時(shí)候,React 會(huì)把我們更新 state 的函數(shù)加入到一個(gè)隊(duì)列里面,然后,按照函數(shù)的順序依次調(diào)用。同時(shí),為每個(gè)函數(shù)傳入 state 的前一個(gè)狀態(tài),這樣,就能更合理的來更新我們的 state 了。


問題所在

那么,這就是傳入對(duì)象來更新 state 會(huì)導(dǎo)致的問題嗎?當(dāng)然,這只是問題之一,還不是主要的問題。

我們之前也說過,我們?cè)谔幚懋惒礁碌臅r(shí)候,需要用到傳入函數(shù)的方式來更新我們的 state。這樣,在更新下一個(gè) state 的時(shí)候,我們能夠正確的獲取到之前的 state,并在在其基礎(chǔ)之上進(jìn)行相應(yīng)的修改。而不是簡(jiǎn)單地執(zhí)行所謂的對(duì)象合并。

所以說,我們建議,在使用 setState 的時(shí)候,采用傳入函數(shù)來更新 state 的方式,這樣也是一個(gè)更合理的方式。


我在 CodePen 上將這兩個(gè)效果組合到了一起,感興趣的話,你可以去試著點(diǎn)擊一下。

See the Pen React Functional setState by Erichain (@Erichain) on CodePen.


References

Functional setState is the future of React

總結(jié)

以上是生活随笔為你收集整理的更合理的 setState()的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。