React進(jìn)階-State&生命周期

state

state是指組件的當(dāng)前狀態(tài)。組件根據(jù)狀態(tài)state呈現(xiàn)不同的UI展示。

一旦狀態(tài)(數(shù)據(jù))更改,組件就會(huì)自動(dòng)調(diào)用render重新渲染UI,通過(guò)this.setState方法來(lái)觸發(fā)。

狀態(tài)組件:當(dāng)更改這個(gè)狀態(tài)(數(shù)據(jù))需要更新組件UI的就需要state。

無(wú)狀態(tài)組件:這種組件沒(méi)有狀態(tài),沒(méi)有生命周期,只是簡(jiǎn)單的接受props渲染生成DOM結(jié)構(gòu)。

無(wú)狀態(tài)組件非常簡(jiǎn)單,開(kāi)銷很低,如果可能的話盡量使用無(wú)狀態(tài)組件。比如使用箭頭函數(shù)定義:

const HelloMessage = (props) => <div> Hello {props.name}</div>;

render(<HelloMessage name="John" />, mountNode);

使用類就允許我們使用其他特性,例如局部狀態(tài)、生命周期鉤子。

//定義一個(gè)類

class Clock extends React.Component {

?????// 添加一個(gè)類構(gòu)造函數(shù)來(lái)初始化狀態(tài)this.state? ? ? ?
? ? ?constructor(props) {? ? ? ? ? ?
????????????super(props);? ? ? ? ? ?
????????????this.state = {date: new Date()};? ? ????
? ? }?

? ? // 當(dāng)組件輸出到DOM后會(huì)執(zhí)行鉤子
? ???componentDidMount() {? ? ??????
?????????// 這是一個(gè)建立定時(shí)器的好地方??
? ? ? ? this.timerID = setInterval(
? ? ? ? ? ?() => this.tick(),
????????????1000?
????????) ;?
?????}?

????componentWillUnmount() {
? ? ? ? // 卸載定時(shí)器
? ? ? ? clearInterval(this.timerID);
? ? }

? ? // 定義一個(gè)方法來(lái)更新組件局部狀態(tài)
? ? tick() {
? ? ? ? this.setState({
? ? ? ? ? ? date: new Date()
????????});
????}

? ? render() {

? ? ? ? return (

? ? ? ? ? ? <div>

? ? ? ? ? ? ? ? <h1>Hello, world!</h1>

? ? ? ? ? ? ? ? <h2>It is {this.state.date.toLocaleTimeString()}.</h2>

? ??????????</div>?

????????);

? ? }

}


ReactDOM.render(

? ? <Clock />,

? ? document.getElementById('root')

};

掛載(componentDidMount):
每當(dāng)Clock組件第一次加載到DOM中的時(shí)候,需要生成這個(gè)定時(shí)器。

卸載(componentWillUnmount):
每當(dāng)Clock生成的這個(gè)DOM被移除的時(shí)候,需要清除這個(gè)定時(shí)器。

實(shí)例講解

? ? 1.當(dāng)<Clock />被傳遞給ReactDOM.render()時(shí),React調(diào)用Clock組件的構(gòu)造函數(shù)。由于Clock需要顯示當(dāng)前時(shí)間,所以使用包含當(dāng)前時(shí)間的對(duì)象來(lái)初始化this.state。我們稍后會(huì)更新此狀態(tài)。

? ? 2.React然后調(diào)用Clock組件的render()方法。這是React了解屏幕上應(yīng)該顯示什么內(nèi)容,然后React更新DOM以匹配Clock的渲染輸出。

? ? 3.當(dāng)Clock的輸出插入到DOM中時(shí),React調(diào)用componentDidMount()生命周期鉤子。在其中,Clock組件要求瀏覽器設(shè)置一個(gè)定時(shí)器,每秒鐘調(diào)用一次tick()。

? ? 4.瀏覽器每秒鐘調(diào)用tick()方法。在其中,Clock組件通過(guò)使用包含當(dāng)前時(shí)間的對(duì)象調(diào)用setState()來(lái)調(diào)度UI更新。通過(guò)調(diào)用setState(),React知道狀態(tài)已經(jīng)改變,并再次調(diào)用render()方法來(lái)確認(rèn)屏幕上應(yīng)當(dāng)顯示什么。這一次,render()方法中的this.state.date將不同,所以渲染輸出將包含更新的時(shí)間,并相應(yīng)地更新DOM。

? ? 5.一旦Clock組件被從DOM中移除,React會(huì)調(diào)用componentWillUnmount()這個(gè)鉤子函數(shù),定時(shí)器也就會(huì)被清除。

!注意:

構(gòu)造函數(shù)是唯一能夠初始化this.state的地方

?// 錯(cuò)誤代碼:此代碼不會(huì)重新渲染組件? ?

this.state.comment = 'Hello';

// 正確代碼

this.setState({comment: 'Hello'});

異步更新?tīng)顟B(tài)

React 可以將多個(gè)setState() 調(diào)用合并成一個(gè)調(diào)用來(lái)提高性能。

因?yàn)?this.props 和 this.state 可能是異步更新的,你不應(yīng)該依靠它們的值來(lái)計(jì)算狀態(tài)。

// 錯(cuò)誤代碼 : 此代碼可能無(wú)法更新計(jì)時(shí)器
this.setState({
? ? counter: this.state.counter + this.props.increment,
});

要修復(fù)它,請(qǐng)使用第二種形式的 setState() 來(lái)接受一個(gè)函數(shù)而不是一個(gè)對(duì)象。該函數(shù)將接收先前的狀態(tài)作為第一個(gè)參數(shù),將此次更新被應(yīng)用時(shí)的props做為第二個(gè)參數(shù):

// 正確代碼?

// 常規(guī)函數(shù)
this.setState( function (preState, props) {
????return {
????????counter: prevState.counter + props.increment
?????};
});

// 箭頭函數(shù)
this.setState ( function (prevState, props) {
? ? return {
? ? ? ? counter: prevState.counter + props.increment
????};
});

狀態(tài)更新合并

當(dāng)你調(diào)用 setState() 時(shí),React 將你提供的對(duì)象合并到當(dāng)前狀態(tài)。

例如,你的狀態(tài)可能包含一些獨(dú)立的變量:

constructor (props) {
? ? super (props);
? ? this.state = {
? ? ? ? posts: [],
? ? ? ? comments: []
????};
}

你可以調(diào)用 setState() 獨(dú)立地更新它們:

componentDidMount () {

? ? fetchPosts().then(response => {
? ? ? ? this.setState({
? ? ? ? ? ? posts: response.posts
????????});
????});

? ? fetchComments().then(response => {
? ? ? ? this.setState({
? ? ? ? ? ? comments: response.comments
????????)};
????});
}

這里的合并是淺合并,也就是說(shuō) this.setState({comments}) 完整保留了 this.state.posts, 但完全替換了 this.state.comments。

數(shù)據(jù)自頂向下流動(dòng)

父組件或子組件都不能知道某個(gè)組件是有狀態(tài)還是無(wú)狀態(tài),并且它們不應(yīng)該關(guān)系某組件是被定義為一個(gè)函數(shù)還是一個(gè)類。

這就是為什么狀態(tài)通常被稱為局部或封裝。除了擁有并設(shè)置它的組件外,其它組件不可訪問(wèn)。

組件可以選擇將其狀態(tài)作為屬性傳遞給其子組件:

<h2>It is {this.state.date.tolocaleTimeString()}.</h2>

這也適用于用戶定義的組件:

<FormattedDate date={this.state.date} />

FormattedDate 組件將在其屬性中接收到 date 值,并且不知道它是來(lái)自 Clock狀態(tài)、還是來(lái)自? Clock的屬性、亦或手工輸入:

function FormattedDate (props) {
? ? return <h2>It is {props.date.toLocaleTimeString()}.</h2>;
}

這通常被稱為 自頂向下 或 單向數(shù)據(jù)流。任何狀態(tài)始終由某些特定組件所有,并且從該狀態(tài)導(dǎo)出的任何數(shù)據(jù)或 UI 只能影響樹(shù)中 下方的組件。

如果你想象一個(gè)組件樹(shù)作為屬性的瀑布,每個(gè)組件的狀態(tài)就像一個(gè)額外的水源,它連接在一個(gè)r任意點(diǎn),但也流下來(lái)。

為了表明所有組件都是真正隔離的,我們可以創(chuàng)建一個(gè) App組件,它渲染三個(gè)Clock:

function App () {
? ? return (
? ? ? ? ?<div>
? ? ? ? ? ? <Clock />
? ? ? ? ? ? <Clock />
? ? ? ? ? ? <Clock />
????????</div>
????);
}

ReactDOM.render(
? ? <App />,
? ? document.getElementById('root')
);

每個(gè) Clock 建立自己的定時(shí)器并且獨(dú)立更新。

在 React應(yīng)用程序中,組件是有狀態(tài)還是無(wú)狀態(tài)被認(rèn)為是可能隨時(shí)間而變化的組件的實(shí)現(xiàn)細(xì)節(jié)??梢栽谟袪顟B(tài)組件中使用無(wú)狀態(tài)組件,反之亦然。

生命周期圖解

生命周期圖解


參考網(wǎng)址:

State&生命周期—React

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • State 和生命周期 考慮前面章節(jié)中時(shí)鐘的例子。 到目前位置,我們僅學(xué)習(xí)了一種更新 UI 的方式。 我們調(diào)用Re...
    soojade閱讀 1,264評(píng)論 0 1
  • 想一下上一節(jié)中那個(gè)滴答計(jì)時(shí)的例子。迄今為止,我們只學(xué)到一種更新UI的方法。我們通過(guò)調(diào)用ReactDOM.rende...
    莫銘閱讀 583評(píng)論 0 0
  • 作為一個(gè)合格的開(kāi)發(fā)者,不要只滿足于編寫(xiě)了可以運(yùn)行的代碼。而要了解代碼背后的工作原理;不要只滿足于自己的程序...
    六個(gè)周閱讀 8,675評(píng)論 1 33
  • $ 前言 ? 最近在考慮框架轉(zhuǎn)型,鑒于作為一名JSer,要時(shí)時(shí)刻刻保持對(duì)新技術(shù)和流行技術(shù)的敏感性,而 React、...
    果汁涼茶丶閱讀 22,161評(píng)論 5 32
  • 不是英雄卻強(qiáng)撐著身體 在茫茫大漠中將根本不存在的魍魎尋覓 手中脆弱的劍是可有可無(wú)的希冀 等待風(fēng)卷沙潮 將自己疲敝的...
    新宿驛閱讀 501評(píng)論 0 0

友情鏈接更多精彩內(nèi)容