【React Native入門系列文章 十】如何從零開始學redux?(附demo)

這裏寫圖片描述
一開始接觸redux時對於它和react的關係理解很混亂:

  • 一會兒是state,一會兒又是store,這兩者到底有什麼關係?
  • 看代碼時,dispatch、reducer、action這三者之間需要跳來跳去,它們到底是什麼關係?爲什麼要這樣設計結構?
  • connect、mapStateToProps、mapDispatchToProps這三者有什麼關係?或者說這三個是幹什麼的?跟redux有什麼關係?
  • action不就是一個function嗎?它和普通的function有區別嗎?爲什麼它就叫action?它return的值return給誰了?
  • redux讓我和react之間隔了一層神祕的面紗,學習成本實在太高了,很多點只是大致知道了,可是就是無法從一個宏觀的角度去理解,結果就是好混亂啊…cry to die…

我們先講一下redux是幹嘛的,它是解決什麼需求的。
先來看看react裏面數據是怎樣傳遞的。

React數據流

react數據傳遞

  1. 可以看到,一般都是Container在設置好state後(this.state設置好)
  2. 把命令一層層地傳遞下去(this.props渲染)
  3. 要是哪個component想要更新頁面內容了
  4. 就得一層層往上報告(通過回調),不能越級
  5. 最好上報到container後,由container去setState修改數據並重新渲染

這個過程是不能越級的,數據傳遞總是讓人覺得不是很靈活。

Redux橫空出世

所以,如果層次不深,組件之間沒有什麼共用數據的話,用react自身的setState其實也可以了。可是,當嵌套一深,或者組件間有一些共用數據時就比較麻煩了,於是就有了redux。

分清兩個state

redux中的state和react中的state完全不是一回事。react中的state是組件內部自己的狀態信息,而redux中的state是redux自己的數據,然後react拿redux的數據來用,其實redux也可以在其他框架下使用,並不是非要跟react一起使用。
簡單畫個圖就像下面這樣
這裏寫圖片描述
這只是一個簡單的示意圖,實際使用並非如此,這個圖示是爲了讓大家理解react中的數據和readux中的數據是獨立的,並沒有半毛錢關係。

Redux中三個重要角色

網上對於redux教程非常多,這裏簡要介紹一下

1. store

store:創建一個store

import { createStore } from 'redux';
const store = createStore(reducer);

用來讓外界獲取redux數據

store.getState

讓外界修改redux中數據

store.dispatch

2. action

action:描述我要幹啥,一般是一個對象的形式,其中有一個type字段是必須要有的。只有被dispatch的action纔有意義,否則它跟一個普通的function沒什麼區別。

3. reducer

reducer:真正去修改redux的state。

const defaultState = {};
const reducer = (state = defaultState, action) => {
  switch (action.type) {
    case Type.REQUEST:
      return {
          ...state,
          action.request
      };
    default: 
      return state;
  }
};

我們在平時使用redux時,都是dispatch一個action,而真正去修改state,然後返回一個全新的state的是reducer。
那麼怎麼去觸發一個action呢?
就是前面提到的store.dispatch,把action作爲dispatch的參數。

store.dispatch({ type:Type.Request,test:"100" })

這樣就可以觸發action,執行reducer,返回一個全新的state了。

Redux和React

到此爲止,redux自己就折騰完了,而redux自己的數據並沒有用,它要把數據交給react用才行,接下來講一講怎麼把數據交給react來用。
上面我們創建了一個對象store,我們要把這個store對象作爲props傳給react,那react就可以用了。
這個store只能有一個,也就只能創建一次,也就是說你在最頂層處創建一個store對象,然後再一層一層地傳下去,才能讓所有組件都能獲取這個store對象,調用它的方法。

獲取redux中的數據

比如說我要在render函數中顯示redux數據,那麼我就可以先獲取它的數據:

store.getState()

然後把這個數據當做props渲染到組件中就行了。

更新redux中的數據

如果要修改它的數據,那就在JSX中調用

store.dispatch({type:Type.Request,test:"100})

相應redux中的變化

那麼這裏問題又來了,你調用了store.dispatch之後redux中數據確實變了,可是react並沒有什麼改變啊。也就是說react中的render函數並沒有被觸發,就好像react中你直接修改react中的state是沒用的,而必須調用react中的setState才能重新渲染。
因此,爲了讓redux的數據一改變我們就重新渲染,redux提供了一個監聽方法

store.subscribe(render)

這個函數就可以監聽redux中state的變化,一旦redux中的state發生了變化,render函數就會被調用,頁面就會被重新渲染

上面這個過程就是手動調用的過程,但這樣調用有點麻煩,因爲要讓所有的組件都能應用store中的數據,那麼所有組件都要把store當做props傳進來,這樣太麻煩了。

React-Redux

這個時候就需要去安裝一些中間件了,還記得你在你的react-native項目中接入redux時安裝的三個庫嗎?
這裏寫圖片描述

npm install –save redux
npm install –save react-redux
npm install –save redux-thunk
npm install –save react-navigation

其中,react-redux就是爲了簡化redux的調用流程(後面我們會一一介紹這幾個庫都做了什麼,爲什麼要引入這幾個庫)。

在react-redux中有兩個比較關鍵的概念:Provider和connect方法

Provider

一般我們都將頂層組件包裹在Provider組件之中,這樣的話,所有組件就都可以在react-redux的控制之下了,但是store必須作爲參數放到Provider組件中去

<Provider store = {store}>
    <Container/>
<Provider>

這個組件的目的是讓所有組件都能夠訪問到redux中的數據
這個比較簡單,我們來講connect方法。

connect方法

connect(mapStateToProps,mapDispatchToProps)(MyComponent)

這兩個參數非常重要,我們來講下。

mapStateToProps

字面含義就是把state映射到props中去,意思就是把redux中的數據映射到react中的props中去
比如一個component想要把網絡請求的數據拿來渲染,就可以在這個component中把redux中的response拿過來用

const mapStateToProps = (state) => {
  return {
    data: state.response
  }
}

然後渲染的時候就可以直接使用this.props.data

class Container extends Component {
    constructor(props){
        super(props);
    }
    render(){
        return(
            <div>this.props.data</div>
        )
    }
}
const mapStateToProps = (state) => {
  return {
    data: state.response
  }
}
export default connect(mapStateToProps)(Container)

這樣就可以實現渲染,把redux中的state變成react中的props

mapDispatchToProps

通過上面的分析,相信這個函數也很好理解,就是把各種dispatch變成props直接使用

const mapDispatchToProps = (dispatch) => {
  return {
    onClick: () => {
      dispatch({
        type: Type.REQUEST,
     test : "100"
      });
    }
  };
}

更改一下Container組件

class Container extends Component {
    constructor(props){
        super(props);
    }
    render(){
        return(
            <div>this.props.data</div>
            <button onClick = {this.props.onClick}>點擊</button>
        )
    }
}
const mapStateToProps = (state) => {
  return {
    data: state.data
  }
}
const mapDispatchToProps = (dispatch) => {
  return {
    onClick: () => {
      dispatch({
        type: Type.REQUEST,
     data : "100"
      });
    }
  };
}
export default connect(mapStateToProps,mapDispatchToProps)(Container);

這樣,當點擊按鈕後,Container組件就會自動更新,而不需要我們手動去store.subscribe訂閱render函數以達到更新頁面的目的,這樣一來我們就不需要一層層傳遞store對象了

tips

這樣隨處都可以使用、修改redux中的數據的方式很方便,但redux推薦的最佳實踐還是在儘可能少的地方使用connect,把邏輯數據相關的都放到容器組件中去處理,把其他的組件都由容器組件所生成的props一層層傳遞下去然後渲染。

redux-thunk

redux-thunk是一個比較流行的redux異步action中間件,比如action中有setTimeOutfetch,那麼就應該用redux-thunk。這裏就不詳細介紹了。

最後

本文適合一些已經對redux有過一定研究,但思路還是比較混亂的小夥伴,這篇文章一定能幫你理清思路。另外歡迎下載集成了redux的react-native的demo

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