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)址: