摘要:傳入一個(gè)對(duì)象的時(shí)候,這個(gè)對(duì)象表示該組件的新?tīng)顟B(tài)。下一節(jié)中我們將介紹小書(shū)配置組件的。
React.js 小書(shū) Lesson10 - 組件的 state 和 setState
本文作者:胡子大哈
本文原文:http://huziketang.com/books/react/lesson10
轉(zhuǎn)載請(qǐng)注明出處,保留原文鏈接以及作者信息
在線閱讀:http://huziketang.com/books/react
state我們前面提到過(guò),一個(gè)組件的顯示形態(tài)是可以由它數(shù)據(jù)狀態(tài)和配置參數(shù)決定的。一個(gè)組件可以擁有自己的狀態(tài),就像一個(gè)點(diǎn)贊按鈕,可以有“已點(diǎn)贊”和“未點(diǎn)贊”狀態(tài),并且可以在這兩種狀態(tài)之間進(jìn)行切換。React.js 的 state 就是用來(lái)存儲(chǔ)這種可變化的狀態(tài)的。
我們還是拿點(diǎn)贊按鈕做例子,它具有已點(diǎn)贊和未點(diǎn)贊兩種狀態(tài)。那么就可以把這個(gè)狀態(tài)存儲(chǔ)在 state 中。修改 src/index.js 為:
import React, { Component } from "react" import ReactDOM from "react-dom" import "./index.css" class LikeButton extends Component { constructor () { super() this.state = { isLiked: false } } handleClickOnLikeButton () { this.setState({ isLiked: !this.state.isLiked }) } render () { return ( ) } } ...
isLiked 存放在實(shí)例的 state 對(duì)象當(dāng)中,這個(gè)對(duì)象在構(gòu)造函數(shù)里面初始化。這個(gè)組件的 render 函數(shù)內(nèi),會(huì)根據(jù)組件的 state 的中的isLiked不同顯示“取消”或“點(diǎn)贊”內(nèi)容。并且給 button 加上了點(diǎn)擊的事件監(jiān)聽(tīng)。
最后構(gòu)建一個(gè) Index ,在它的 render 函數(shù)內(nèi)使用 LikeButton 。然后把 Index 渲染到頁(yè)面上:
... class Index extends Component { render () { return (setState 接受對(duì)象參數(shù)) } } ReactDOM.render(, document.getElementById("root") )
在 handleClickOnLikeButton 事件監(jiān)聽(tīng)函數(shù)里面,大家可以留意到,我們調(diào)用了 setState 函數(shù),每次點(diǎn)擊都會(huì)更新 isLiked 屬性為 !isLiked,這樣就可以做到點(diǎn)贊和取消功能。
setState 方法由父類 Component 所提供。當(dāng)我們調(diào)用這個(gè)函數(shù)的時(shí)候,React.js 會(huì)更新組件的狀態(tài) state ,并且重新調(diào)用 render 方法,然后再把 render 方法所渲染的最新的內(nèi)容顯示到頁(yè)面上。
注意,當(dāng)我們要改變組件的狀態(tài)的時(shí)候,不能直接用 this.state = xxx 這種方式來(lái)修改,如果這樣做 React.js 就沒(méi)辦法知道你修改了組件的狀態(tài),它也就沒(méi)有辦法更新頁(yè)面。所以,一定要使用 React.js 提供的 setState 方法,它接受一個(gè)對(duì)象或者函數(shù)作為參數(shù)。
傳入一個(gè)對(duì)象的時(shí)候,這個(gè)對(duì)象表示該組件的新?tīng)顟B(tài)。但你只需要傳入需要更新的部分就可以了,而不需要傳入整個(gè)對(duì)象。例如,假設(shè)現(xiàn)在我們有另外一個(gè)狀態(tài) name :
... constructor (props) { super(props) this.state = { name: "Tomy", isLiked: false } } handleClickOnLikeButton () { this.setState({ isLiked: !this.state.isLiked }) } ...
因?yàn)辄c(diǎn)擊的時(shí)候我們并不需要修改 name,所以只需要傳入 isLiked 就行了。Tomy 還是那個(gè) Tomy,而 isLiked 已經(jīng)不是那個(gè) isLiked 了。
setState 接受函數(shù)參數(shù)這里還有要注意的是,當(dāng)你調(diào)用 setState 的時(shí)候,React.js 并不會(huì)馬上修改 state。而是把這個(gè)對(duì)象放到一個(gè)更新隊(duì)列里面,稍后才會(huì)從隊(duì)列當(dāng)中把新的狀態(tài)提取出來(lái)合并到 state 當(dāng)中,然后再觸發(fā)組件更新。這一點(diǎn)要好好注意??梢泽w會(huì)一下下面的代碼:
... handleClickOnLikeButton () { console.log(this.state.isLiked) this.setState({ isLiked: !this.state.isLiked }) console.log(this.state.isLiked) } ...
你會(huì)發(fā)現(xiàn)兩次打印的都是 false,即使我們中間已經(jīng) setState 過(guò)一次了。這并不是什么 bug,只是 React.js 的 setState 把你的傳進(jìn)來(lái)的狀態(tài)緩存起來(lái),稍后才會(huì)幫你更新到 state 上,所以你獲取到的還是原來(lái)的 isLiked。
所以如果你想在 setState 之后使用新的 state 來(lái)做后續(xù)運(yùn)算就做不到了,例如:
... handleClickOnLikeButton () { this.setState({ count: 0 }) // => this.state.count 還是 undefined this.setState({ count: this.state.count + 1}) // => undefined + 1 = NaN this.setState({ count: this.state.count + 2}) // => NaN + 2 = NaN } ...
上面的代碼的運(yùn)行結(jié)果并不能達(dá)到我們的預(yù)期,我們希望 count 運(yùn)行結(jié)果是 3 ,可是最后得到的是 NaN。但是這種后續(xù)操作依賴前一個(gè) setState 的結(jié)果的情況并不罕見(jiàn)。
這里就自然地引出了 setState 的第二種使用方式,可以接受一個(gè)函數(shù)作為參數(shù)。React.js 會(huì)把上一個(gè) setState 的結(jié)果傳入這個(gè)函數(shù),你就可以使用該結(jié)果進(jìn)行運(yùn)算、操作,然后返回一個(gè)對(duì)象作為更新 state 的對(duì)象:
... handleClickOnLikeButton () { this.setState((prevState) => { return { count: 0 } }) this.setState((prevState) => { return { count: prevState.count + 1 } // 上一個(gè) setState 的返回是 count 為 0,當(dāng)前返回 1 }) this.setState((prevState) => { return { count: prevState.count + 2 } // 上一個(gè) setState 的返回是 count 為 1,當(dāng)前返回 3 }) // 最后的結(jié)果是 this.state.count 為 3 } ...
這樣就可以達(dá)到上述的利用上一次 setState 結(jié)果進(jìn)行運(yùn)算的效果。
setState 合并上面我們進(jìn)行了三次 setState,但是實(shí)際上組件只會(huì)重新渲染一次,而不是三次;這是因?yàn)樵?React.js 內(nèi)部會(huì)把 JavaScript 事件循環(huán)中的消息隊(duì)列的同一個(gè)消息中的 setState 都進(jìn)行合并以后再重新渲染組件。
深層的原理并不需要過(guò)多糾結(jié),你只需要記住的是:在使用 React.js 的時(shí)候,并不需要擔(dān)心多次進(jìn)行 setState 會(huì)帶來(lái)性能問(wèn)題。
下一節(jié)中我們將介紹《React.js 小書(shū) Lesson11 - 配置組件的 props》。
文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/89664.html
摘要:一個(gè)組件的顯示形態(tài)由多個(gè)狀態(tài)決定的情況非常常見(jiàn)。我們順利地消除了手動(dòng)的操作。非一般的暴力,因?yàn)槊看味贾匦聵?gòu)造新增刪除元素,會(huì)導(dǎo)致瀏覽器進(jìn)行大量的重排,嚴(yán)重影響性能。下一節(jié)小書(shū)前端組件化三抽象出公共組件類我們把這個(gè)通用模式抽離到一個(gè)類當(dāng)中。 React.js 小書(shū) Lesson3 - 前端組件化(二):優(yōu)化 DOM 操作 本文作者:胡子大哈本文原文:http://huziketang....
摘要:例如,上面設(shè)置了的為,在中被初始化為空字符串。如何向傳遞的數(shù)據(jù)父組件只需要通過(guò)給子組件傳入一個(gè)回調(diào)函數(shù)。當(dāng)用戶點(diǎn)擊發(fā)布按鈕的時(shí)候,調(diào)用中的回調(diào)函數(shù)并且將傳入該函數(shù)即可。下一節(jié)中我們將介紹小書(shū)實(shí)戰(zhàn)分析評(píng)論功能三。 React.js 小書(shū) Lesson15 - 實(shí)戰(zhàn)分析:評(píng)論功能(二) 本文作者:胡子大哈本文原文:http://huziketang.com/books/react/les...
摘要:多次的隱藏和顯示會(huì)讓重新構(gòu)造和銷毀組件,每次構(gòu)造都會(huì)重新構(gòu)建一個(gè)定時(shí)器。而銷毀組件的時(shí)候沒(méi)有清除定時(shí)器,所以你看到報(bào)錯(cuò)會(huì)越來(lái)越多。例如清除該組件的定時(shí)器和其他的數(shù)據(jù)清理工作。下一節(jié)中我們將介紹小書(shū)更新階段的組件生命周期。 React.js 小書(shū) Lesson19 - 掛載階段的組件生命周期(二) 本文作者:胡子大哈本文原文:http://huziketang.com/books/re...
摘要:最后抽離出來(lái)了一個(gè)類,可以幫助我們更好的做組件化。一個(gè)組件有自己的顯示形態(tài)上面的結(jié)構(gòu)和內(nèi)容行為,組件的顯示形態(tài)和行為可以由數(shù)據(jù)狀態(tài)和配置參數(shù)共同決定。接下來(lái)我們開(kāi)始正式進(jìn)入主題,開(kāi)始正式介紹。下一節(jié)鏈接直達(dá)小書(shū)基本環(huán)境安裝 React.js 小書(shū) Lesson4 - 前端組件化(三):抽象出公共組件類 本文作者:胡子大哈本文原文:http://huziketang.com/books...
摘要:默認(rèn)配置上面的組件默認(rèn)配置我們是通過(guò)操作符來(lái)實(shí)現(xiàn)。但這并不意味著由決定的顯示形態(tài)不能被修改。組件可以在內(nèi)部通過(guò)獲取到配置參數(shù),組件可以根據(jù)的不同來(lái)確定自己的顯示形態(tài),達(dá)到可配置的效果。下一節(jié)中我們將介紹小書(shū)。 React.js 小書(shū) Lesson11 - 配置組件的 props 本文作者:胡子大哈本文原文:http://huziketang.com/books/react/lesso...
閱讀 5453·2021-09-22 15:50
閱讀 1937·2021-09-02 15:15
閱讀 1233·2019-08-29 12:49
閱讀 2606·2019-08-26 13:31
閱讀 3521·2019-08-26 12:09
閱讀 1277·2019-08-23 18:17
閱讀 2803·2019-08-23 17:56
閱讀 3003·2019-08-23 16:02