目錄
- 1.
state
屬性- 1.1
state
屬性的介紹 - 1.2
state
的使用
- 1.1
- 2.
setState()
方法- 2.1 第一個參數(shù):
updater
函數(shù) - 2.2 第二個參數(shù):
callback
- 2.1 第一個參數(shù):
- 3.正確操作 state
- 3.1 不要使用
this.state
來直接修改state
- 3.2 狀態(tài)更新可能是異步的
- 3.3 狀態(tài)更新是一個合并的過程
- 3.1 不要使用
- 4.單向數(shù)據(jù)流
- 5.完整示例代碼
state
屬性是 React 組件用來更新數(shù)據(jù)的核心特性,也是我們平時見得最多的屬性之一,那么你對 state
又了解多少呢李根?
1. state
屬性
1.1 state
屬性的介紹
我們使用兩種數(shù)據(jù)來控制一個組件:props
和 state
穷劈。props
是在父組件中指定,而且一經(jīng)指定乱陡,在被指定的組件的生命周期中則不再改變。 對于需要改變的數(shù)據(jù),我們需要使用 state
沙廉。
state
屬性主要用來存儲組件自身需要的數(shù)據(jù),是組件自己私有的臼节,我們一般通過修改 state
屬性的值來更新數(shù)據(jù)撬陵,React 內(nèi)部會監(jiān)聽 state
的變化珊皿,一旦發(fā)生變化就會主動觸發(fā)組件的 render()
方法來更新 Dom 結(jié)構(gòu)。
state
應(yīng)該是一個 JavaScript 對象巨税。
1.2 state
的使用
一般來說蟋定,你需要在 constructor()
方法中初始化 state
(這是ES6的寫法,ES5 中一般在 getInitialState()
方法中來初始化 state
)草添,然后在需要修改時調(diào)用 setState()
方法驶兜。
不要使用 this.state
來修改 state
屬性值,應(yīng)該調(diào)用 setState()
方法远寸,this.state
是不可變的抄淑。
2. setState()
方法
setState()
的完整表達式
setState(updater, [callback])
setState()
方法會把對組件 state 的改變加入到隊列中,并且告訴 React 這個組件及其子組件需要重新渲染驰后。
2.1 第一個參數(shù):updater
函數(shù)
setState(updater, callback)
方法的第一個參數(shù)是一個固定格式的 updater
函數(shù):
(prevState, props) => stateChange
prevState
是一個對之前狀態(tài)(previous state)的引用肆资,我們是不能直接修改這個參數(shù)的值,要想修改 state
的值灶芝,我們應(yīng)該根據(jù) prevState
和 props
參數(shù)來創(chuàng)建一個新的 JavaScript 對象郑原。
例如:
this.setState((prevState, props) => {
return {counter: prevState.counter + props.step};
});
你也可以傳一個對象而不是函數(shù),來作為setState(updater, callback)
方法的第一個參數(shù)夜涕,React 會將該參數(shù) merge 到 state 中犯犁。
例如:
this.setState({quantity: 2});
2.2 第二個參數(shù):callback
setState(updater, callback)
方法的第二個參數(shù) callback
是一個可選參數(shù)。
為了更好的性能表現(xiàn)女器,React 并不能保證 setState()
一被調(diào)用 state 就能更新栖秕。所以,如果在調(diào)用 setState()
之后晓避,馬上就讀取 this.state
的值的話簇捍,可能會出現(xiàn)誤差。
因此俏拱,這種情況下暑塑,推薦使用 componentDidUpdate
或者 setState(updater, callback)
方法的 callback
來獲取最新的狀態(tài)。React 官方更推薦使用 componentDidUpdate()
锅必,而不是 callback
來監(jiān)聽 update 事件(注: 除非 shouldComponentUpdate()
方法返回 false
事格,setState()
將永遠(yuǎn)都會引發(fā)重新渲染)。
3. 正確操作 state
3.1 不要使用 this.state
來直接修改 state
記住搞隐,
this.state
是不可變的驹愚。
不要使用 this.state
來修改 state
屬性值:
// Wrong
this.state.comment = 'Hello';
應(yīng)該調(diào)用 setState()
方法:
// Correct
this.setState({comment: 'Hello'});
3.2 狀態(tài)更新可能是異步的
考慮到性能問題,如果在同一個周期內(nèi)劣纲,調(diào)用了多次逢捺,React 可能會將多個 setState()
方法的調(diào)用批量合成一次更新。比如癞季,你在一個周期內(nèi)劫瞳,對一個數(shù)值進行多次累加倘潜,就會出現(xiàn)類似于下面的這種情況:
Object.assign(
previousState,
{quantity: state.quantity + 1},
{quantity: state.quantity + 1},
...
)
這也就意味著,后面的調(diào)用會覆蓋掉上一次調(diào)用后的修改的 state 值志于,因此 quantity 只累加了 1 次涮因。
考慮到 this.props
和this.state
可能是異步更新的,所以伺绽,每次調(diào)用 setState()
方法時养泡,最好不要依賴于 this.props
和this.state
來計算最新的 state
。
總之奈应,如果后面的狀態(tài)依賴于之前的狀態(tài)瓤荔,建議使用 updater
函數(shù):
// Correct
this.setState((prevState, props) => {
return {quantity: prevState.quantity + 1};
});
上面用的是 箭頭函數(shù) 的形式,其實用普通的函數(shù)也是一樣的效果:
// Correct
this.setState(function(prevState, props) {
return {
quantity: prevState.quantity + 1;
};
});
3.3 狀態(tài)更新是一個合并的過程
當(dāng)你調(diào)用 setState()
方法時钥组,React 會將將你當(dāng)前所提供的對象合并到當(dāng)前的狀態(tài)中输硝。
例如:
constructor(props) {
super(props);
this.state = {
posts: [],
comments: []
};
}
componentDidMount() {
fetchComments().then(response => {
this.setState({
comments: response.comments
});
});
}
在上面??的例子中, state 的更新只是替換了 comments
程梦,posts
是不會受到任何影響的点把。
4.單向數(shù)據(jù)流
父組件和子組件之間不能通過 state 來交互,父組件只能將自己的 state 值傳給子組件的 props屿附。這種數(shù)據(jù)傳遞的方式通常被稱為 “自頂向下(top-down)”或者“單向(unidirectional)”數(shù)據(jù)流郎逃。
任何 state 都是由一個特定的組件所擁有的,任何由 state 驅(qū)動的數(shù)據(jù)或者 UI 只會影響到該組件的子組件挺份。
如果你將組件樹想象成一個 props 瀑布褒翰,那么每個組件的狀態(tài)就像是那個組件水源上的附屬品,但是也是向下流動的匀泊。
5. 完整示例代碼
'use strict';
import React, { Component, } from 'react';
import {
AppRegistry,
StyleSheet,
View,
Text,
TouchableOpacity,
} from 'react-native';
export default class StateDemo extends Component {
render() {
return <Container style={styles.container} />;
}
}
class Container extends Component {
constructor() {
super();
// 設(shè)置初始狀態(tài)
this.state = {
showText: true,
};
}
render() {
// 根據(jù)狀態(tài)決定展示什么文字
var text = (this.state.showText == true) ? 'Hello' : "";
var buttonTitle = (this.state.showText == true) ? 'Hide' : "Show";
return (
<View style={styles.container}>
<Text style={styles.text}>{text}</Text>
<TouchableOpacity
onPress = {() => {
// 更新狀態(tài)
this.setState(
previousState => {
return { showText: !previousState.showText };
}
);
}}>
<Text style={styles.buttonTitle}>{buttonTitle}</Text>
</TouchableOpacity>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: 'yellow',
alignItems: 'center',
},
text: {
marginTop: 200,
fontSize: 30,
textAlign: 'center',
},
buttonTitle: {
width: 70,
marginTop: 10,
fontSize: 20,
textAlign: 'center',
backgroundColor: 'green',
},
});
延伸閱讀
- React API Reference: React.Component
- React API Reference: State and Lifecycle
- React Native 官方文檔:State
- 《React Native 入門與實戰(zhàn)》