react-native 之 state 和 props 以及 redux 和 react-redux

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的定義方式。通過改變dataSourceisRefresh的值就能激發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的使用以及執行原理。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章