BG:
目前的Component仍然在react框架中嗦董,也就是說(shuō)React Native使用的Component是react框架中的組件,而Component有兩大數(shù)據(jù)管理核心State和Props瘦黑。也就是說(shuō)即使你僅僅想用React Native開(kāi)發(fā)APP京革,你也需要去了解React的相關(guān)知識(shí),比如Component幸斥、State和Props匹摇,本文主要介紹State的使用。
React 把組件看成是一個(gè)狀態(tài)機(jī)(State Machines)甲葬。通過(guò)與用戶的交互廊勃,實(shí)現(xiàn)不同狀態(tài),然后渲染 UI经窖,讓用戶界面和數(shù)據(jù)保持一致供搀。
React 里,只需更新組件的 state钠至,然后根據(jù)新的 state 重新渲染用戶界面(不要操作 DOM)。
一.初始化 this.state
在組件的 類構(gòu)造函數(shù)(class constructor) 中初始化 this.state
:
export default class StatePage extends Component {
constructor(props) {
super(props);
this.state = {
name : '張三',
age:0,
};
};
}
注意:唯一可以分配 this.state 的地方是構(gòu)造函數(shù)胎源。
二棉钧、this.setState()
1.setState的原理:
這只是一個(gè)簡(jiǎn)單的原理圖,setState背后的實(shí)現(xiàn)的詳細(xì)過(guò)程需要借助React.js源代碼和調(diào)用堆棧去查看涕蚤。
2.setState引發(fā)的Component的更新過(guò)程:
setState會(huì)觸發(fā)Component的以下4個(gè)生命周期方法宪卿,并依次執(zhí)行:
shouldComponentUpdate
componentWillUpdate
render
componentDidUpdate
shouldComponentUpdate
返回的是true
orfalse
決定了當(dāng)前組件是否在state或props改變后是否進(jìn)行render。shouldComponentUpdate
默認(rèn)返回的是true
万栅,也就是當(dāng)前組件在setState或props改變后會(huì)進(jìn)行render佑钾,刷新UI。
3.this.state何時(shí)才被更新烦粒?
要想觀察this.state何時(shí)被更新休溶,需要我們?nèi)ピ谙嚓P(guān)生命周期方法中去進(jìn)行打印,而觀察的結(jié)果是這樣的:
當(dāng)shouldComponentUpdate
返回true時(shí):
1.當(dāng)shouldComponentUpdate
函數(shù)被調(diào)用的時(shí)候扰她,this.state沒(méi)有得到更新;
2.當(dāng)componentWillUpdate
函數(shù)被調(diào)用的時(shí)候兽掰,this.state依然沒(méi)有得到更新;
3.直到render
函數(shù)被調(diào)用的時(shí)候方面,this.state才得到更新油讯。
當(dāng)shouldComponentUpdate
返回false時(shí):
1.本次shouldComponentUpdate
函數(shù)被調(diào)用的時(shí)候欧漱,this.state沒(méi)有得到更新;
2.當(dāng)shouldComponentUpdate函數(shù)返回false攘蔽,此時(shí)更新過(guò)程會(huì)被中斷揪惦,render函數(shù)也不會(huì)被調(diào)用,但這時(shí)候React不會(huì)放棄掉對(duì)this.state的更新的壹哺,所以雖然不調(diào)用render倾剿,依然會(huì)更新this.state,在下次觸發(fā)shouldComponentUpdate
時(shí)可以看到打印的this.state已經(jīng)更新熏挎。
綜上所述:直到render函數(shù)調(diào)用時(shí)(或者shouldComponentUpdate返回false速勇,再次在shouldComponentUpdate函數(shù)中)才得到更新后的this.state。
三婆瓜、setState使用:
執(zhí)行setState時(shí)快集,會(huì)將需要更新的state合并后放入狀態(tài)隊(duì)列,而不會(huì)立刻更新state廉白,隊(duì)列機(jī)制可以批量更新state个初。
1. setState的幾種場(chǎng)景:
(1).批量更新的典型,合并猴蹂、異步setState:
clickBtn=()=>{
this.setState({
name:'王五',
});
this.setState({
age:30
});
this.setState({
age:20
});
}
合并是淺合并院溺,所以 第二次this.setState({age }) 不會(huì)把 this.state.name 沖掉,但會(huì)完全替換上一次this.state.age 的值磅轻。
以上代碼只會(huì)觸發(fā)1次render,并且在render函數(shù)調(diào)用時(shí)this.state.age的值才被更新且是20珍逸。也就是多次的setState會(huì)被合并,并且單個(gè)屬性的多次setState只有最后一次的更新會(huì)生效聋溜。
(2).非批量更新的典型谆膳,定時(shí)器中setState:
componentWillMount() {
console.log(`StatePage--componentWillMount`);
this.testTimer = setTimeout(
()=>{
this.setState({
age: this.state.age + 1,
});
this.setState({
age: this.state.age + 1,
});
this.setState({
age: this.state.age + 1,
});
},
0,
);
}
以上代碼會(huì)觸發(fā)3次render,并且每次this.state.age的值都會(huì)加1。
定時(shí)器中setState,對(duì)應(yīng)了上面setState的原理圖中的非bathUpdate分支撮躁。
(3)漱病、依賴this.props 和 this.state的值更新this.state:
因?yàn)?this.props 和 this.state 可能是異步更新的,你不能依賴他們的值計(jì)算下一個(gè)state(狀態(tài))把曼。
錯(cuò)誤寫(xiě)法:
this.setState({
age: this.state.age + this.props.baseAge,
});
以上代碼可能導(dǎo)致 age(年齡)更新失斞蠲薄!
正確寫(xiě)法:
setState()接收一個(gè)函數(shù)嗤军,而不是一個(gè)對(duì)象注盈。該函數(shù)接收前一個(gè)狀態(tài)值作為第 1 個(gè)參數(shù),前一個(gè)props值作為第 2 個(gè)參數(shù)叙赚, 并將更新后的值進(jìn)行回調(diào)老客,也就是利用上一次狀態(tài)的age和props中的age進(jìn)行計(jì)算來(lái)更新的age:
this.setState((state, props) => ({
age: state.age + props.baseAge,
}));
在上面使用了一個(gè)箭頭函數(shù),但是也可以使用一個(gè)常規(guī)的函數(shù):
// 正確
this.setState(function(state, props) {
return {
counter:state.age + props.baseAge,
};
});
(4)震叮、setState回調(diào)函數(shù):
this.setState({age: 23}, ()=> {
console.log(this.state.age);//23
});
`setState的回調(diào)函數(shù)中可以獲取到已經(jīng)更新后的state沿量,相當(dāng)于componentDidUpdate函數(shù)或render函數(shù)中獲取更新后的state。
四冤荆、數(shù)據(jù)自頂向下流動(dòng)
無(wú)論作為父組件還是子組件朴则,它都無(wú)法獲悉一個(gè)組件是否有狀態(tài),同時(shí)也不需要關(guān)心另一個(gè)組件是定義為函數(shù)組件還是類組件。
這就是 state(狀態(tài)) 經(jīng)常被稱為 本地狀態(tài) 或 封裝狀態(tài)的原因乌妒。 它不能被擁有并設(shè)置它的組件 以外的任何組件訪問(wèn)汹想。
一個(gè)組件可以選擇將 state(狀態(tài)) 向下傳遞,作為其子組件的 props(屬性):
<StateComponent name={this.state.name} age = {this.state.age}/>
子組件StateComponent
通過(guò) props(屬性) 接收了父組件
傳遞的name和age的值撤蚊,但它仍然不能獲知該值是來(lái)自于父組件
的 state(狀態(tài)) 古掏,還是 父組件
的 props(屬性),或者是父組件
中直接手動(dòng)創(chuàng)建的侦啸。
五槽唾、總結(jié):
1.不要使用 this.state 來(lái)直接修改 state,state值雖然會(huì)被更改光涂,但不會(huì)觸發(fā)render庞萍;
2.setState可能是異步的,不會(huì)立刻改變React組件中state的值忘闻;
3.React 為了優(yōu)化性能钝计,有可能會(huì)將多個(gè) setState() 調(diào)用合并為一次更新
4.setState通過(guò)引發(fā)一次組件的更新過(guò)程來(lái)引發(fā)重新繪制;
5.不能依賴this.props 和 this.state的值計(jì)算下一個(gè)state(狀態(tài))齐佳;
6.定時(shí)器中多次setState不會(huì)被合并私恬,state的值會(huì)被立即更新;
7.setState可能會(huì)引發(fā)不必要的渲染炼吴,你可以在shouldComponentUpdate(object nextProps, object nextState)函數(shù)中根據(jù)實(shí)際情況決定是否觸發(fā)render本鸣。