Component 中 state 和 props 的區別;
組件Component中狀態state和屬性props的區別
state | props |
---|---|
state是在組件內部定義的一個特殊對象{} ,既起到組件內部的一種緩存作用, 也具備由於state變化而激發生命週期中渲染的方法 render()被回調的作用。且使用域僅限於組件內部。 |
props是組件屬性,連接了外部父組件和組件內部的使用域。 它的改變激發聲明週期方法componentWillReceiveProps(nextProps) 和渲染的方法render()逐次被回調。連接外部父組件, 可以通過父組件向其傳遞value、function等,連接內部組件, this.props緩存了當前組件的所有props屬性內容 即 {value, function}=this.props; |
代碼解釋 props
/**
* 通過封裝 FlatList 自定義一個列表組件
*/
export default class MyFlatList extends Component {
constructor(props) {
super(props);
}
...
/**
*象組件FlatList中的
*ref、ListHeaderComponent、ItemSeparatorComponent、
*data、keyExtractor、onRefresh、refreshing等都是props屬性;
*
* 象這種樣式的定義 this.props.itemSeparator、
* this.props.onRefresh、this.props.refreshing、this.props.onLoadMore等
* 屬於自定義組件MyFlatList的屬性,是我們依照FlatList所定義的。
* 類似象外部開放的接口一樣,就像這裏FlatList使用自己的
* 屬性ListHeaderComponent、ItemSeparatorComponent、data等一樣來使用;
* @returns {XML}
*/
render() {
return (<View style={{flex: 1, backgroundColor: Colors.bg}}>
<FlatList
ref={(flatlist) => this.flatlist = flatlist}
ListHeaderComponent={this._header}
renderItem={this._renderItem}
ItemSeparatorComponent={this.props.itemSeparator}
data={this.props.data}
keyExtractor={this._keyExtractor}
onRefresh={this.props.onRefresh}
refreshing={this.props.refreshing}
onEndReachedThreshold={0.1}
onEndReached={this.props.onLoadMore}
initialNumToRender={3}
getItemLayout={(data, index) => ({
length: 250, offset: (250 + 10) * index, index
})}
/>
</View>);
}
}
這是使用MyFlatList,來看下它的這個props
export default class FlatlistScreen extends Component {
...
/**
*這裏MyFlatList的 itemSeparator、data、onRefresh 、refreshing 、onLoadMore
*就是FlatList中使用this.props.xxx來定義的。
* @returns {XML}
*/
render() {
return (<View style={styles.container}>
...
<MyFlatList
{...this.props}
itemSeparator={() => this.separator()}
data={this.state.dataSource}
onRefresh = {()=>this.onRefresh()}
refreshing = {this.state.isRefresh}
onLoadMore = {()=>this.onLoadMore()}
/>
</View>);
}
}
除了以上,如果是對數據內容的props屬性的變化,如上面代碼的data變化,必然會激發MyFlatList組件生命週期方法componentWillReciveProps回調,這裏我們可以在render方法回調前,對數據再次進行判斷處理。
**這就是props屬性功能和作用!!**
代碼解釋 state
export default class FlatlistScreen extends Component {
constructor(props) {
super(props);
this.unmount = false;
this.state = ({
dataSource : [],
isRefresh: true,
});
}
...
/**
* 功能:使用箭頭函數,不使用bind;因爲bind函數每調用一次就會創建一個新的函數
*/
onRefresh() {
this.setState({
isRefresh: true,
});
//功能:製造刷新效果
this.interval = setInterval(() => {
clearInterval(this.interval);
//功能:製造上拉加載更多的效果
const data = [];
for (let i = 0; i < 8; i++) {
data.push({id: i, title: '親子旅遊日帶娃兒玩' + i + '折起', state: '已過期', date: '2018/06/0' + (i - 8)},)
}
this.setState({
dataSource: data,
isRefresh: false,
});
}, 2000)
}
...
render() {
return (<View style={styles.container}>
...
<MyFlatList
{...this.props}
itemSeparator={() => this.separator()}
data={this.state.dataSource}
onRefresh = {()=>this.onRefresh()}
refreshing = {this.state.isRefresh}
onLoadMore = {()=>this.onLoadMore()}
/>
</View>);
}
}
看構造方法這裏
this.state = ({
dataSource : [],
isRefresh: true,
});
這就是state的定義方式。通過改變dataSource、isRefresh的值就能激發render再次渲染組件。
比如這裏的onRefresh方法使用了
this.setState({
dataSource: data,
isRefresh: false,
});
來控制改變state的時機,來控制組件渲染的時機。
**這就是狀態state的使用!!**
react-native 與 Redux 的配合使用;
在Redux使用中,一些必知的概念
Redux | state | action | reducers |
---|---|---|---|
Redux 是 JavaScript 狀態容器, 提供可預測化的狀態管理。 使用 Redux 的一個益處, 就是它讓 state 的變化過程變的可預知和透明。 |
以一個對象樹的形式儲存在於一個單一的 store 中, 惟一改變 state 的辦法是觸發 action。 |
一個描述發生什麼的指示器對象。 action 內必須使用一個字符串類型的 type 字段, 來表示將要執行的動作。 且應該儘量減少在 action 中傳遞的數據; |
描述 action 如何改變 state 樹。 reducer 就是一個純函數,接收舊的 state 和 action,返回新的 state。 |
這裏是我基於Redux實現的已給簡單操作流程源碼
結合源碼+圖例,分析下redux的執行操作流程,解讀redux是怎樣原理!
登錄操作執行圖
現在定位在登錄頁面,處於未登錄狀態,需要點擊登錄操作。
圖並結合源碼分析
登錄頁面的部分源碼,展示了登錄頁面的UI
從源碼中50行看到,點擊登錄按鈕,則調用方法login()
,而login()這個方法是從this.props
中解構賦值拿出來的,就是源碼37行所示。
疑問1? this.props
中的login()是從哪裏來的,怎麼會在this.props中?!
接着看同一js文件中的代碼片段
這裏有一個方法非常的重要connect()
,她是幹什麼的,這裏可以解答。
簡單的說是,就我們所看到的代碼從64到74行,connect()裏面有兩個回調函數,第一個回調的是state(Login頁面的state),第二回調的是dispatch(Login頁面用來進行分發登錄操作的Action)。通過connect()()
實現了 回調函數中 status、isSuc、user 和 login() 他們與當前的組件(登錄頁面)的this.props綁定,也就是他們被注入到了this.props中。
所以,點擊登錄的執行流程是這樣的:
點擊登錄按鈕——>調用this.props中的login方法——>派發登錄操作的action ——>.. reducer處理…導致store的state樹中登錄組件的state發生變化 … ——>源碼中65行執行回調,同時UI將會執行重新的刷新、渲染——>渲染過程中需要的內容,從回調中的state中獲取、賦值。
繼續深入…
登錄功能的Action中有兩類內容,一是需要傳遞的用戶數據對象
二是派發的Action構建函數
圖中可以清晰看到,Action有兩種實現方式,其中最後一種是異步的Action構建函數,前面則是同步的Action構建函數;通常異步的Action中會調用同步的Action。而同步的Action有一個特點就是有一個約定成俗的字段叫type,標識着Action的通知類型。
當執行登錄操作,使用redux進行登錄操作的action進行派發的時候,調用了異步的Action,異步的通知由在內部執行異步操作,調用同步的action。執行到這裏,action就會被分發到哪裏呢??reducer
reducer也分爲兩部分,一是登錄頁面內容展示登錄組件的state
是一個登錄操作在執行到reducer時的處理,進行復制、賦值、填充的state模型的數據對象,store樹中的一個對象。
reducer的處理也很簡單,就是根據action的指定處理方式type,進行處理。處理完成之後,返回一個新的state對象。看源碼是不是這樣的?!
執行處理到這裏,想到你已經發起疑問了。疑問2?總覺得,到reducer處理之後與組件容器那兒回調,直到頁面再次渲染,沒有什麼關聯??!它們到底是怎麼建立關係的呢?
當然是通過Redux,以及處理異步action需要用到的中間件(標準的做法是使用 Redux Thunk 中間件)。
看這裏,首先是集合管理action的處理,對reducer的管理
然後把對reduer的管理,以及處理結果再交給redux
並且也同時,把上面的兩個reduer對應的處理結果state,作爲store樹的分支,綁定到了store中,進行統一管理和處理。而且還有一點很關鍵、很重要!也是急需解決的重要疑問——store樹長什麼樣子??
經過我的實踐和測試對比得出結論,
store樹
中的登錄組件的state,其數據內容的樣子是和上圖中源碼第10行
rootReduer
中的數據結構LoginIn是對應的。也就是說他們是互相映射的。即,
store與rootReduer
在數據結構上是一致的,
store樹
就是通過這樣的
rootReduer
中一條條
{key:value}
數據拼湊到一起所組成的對象。
如果有點疑問,自己可以動手試一試,並用下圖再加深下印象
store樹是用來管理組件state數據的,好,因爲我們使用了全局提供store的方式進行了處理,
store中的屬性,我們可以在項目中進行全局使用。
所以,在connect()()
代碼塊中,當state發生變化,產生回調,我們可以通過state.LoginIn.status、state.LoginIn.isSuc、state.LoginIn.user來指定拿到當前組件對應的state數據。而state.LoginIn的調用方式就是從store樹中取出LoginIn對應的state,而LoginIn是哪來的?也許內容有點多,蒙圈了,其實就在原先這裏第11行代碼。
所以,我之前總結的結論,store樹中的登錄組件的state,其數據內容的樣子是和上圖中源碼第10行
rootReduer
中的數據結構LoginIn是對應的。也就是說他們是互相映射的。
store與rootReduer 在數據結構上是一致的, store樹 就是通過這樣的rootReduer 中一條條 {key:value} 數據拼湊到一起所組成的對象。
是正確的!到這裏則回答了上面的疑問2?,同時也解決了Redux的使用以及執行原理。