react-native redux使用指南

demo 地址:react

https://github.com/chriszhou666666/react-native-reduxgit

1 >> 什麼是redux ? 你的項目需不須要redux?github

有個大神說過? 若是你以爲你的項目不須要redux, 那麼你就真的不須要去用 redux.npm

redux 究竟是什麼呢? 其實就是用來統一管理整個應用 State 的, 將全部的 state 變化進行統一的流程處理, 使應用的 state變化清晰可見.redux

如圖 : 使用redux和不使用組件之間的通訊方式的不一樣 react-native

 

 

在React中,數據在組件中是經過 props 單向流動的。數據從父組件流向子組件,因爲這個特徵,兩個兄弟組件之間的通訊並非那麼清楚。
React並不建議直接採用組件到組件的通訊方式,須要提一點的是, 在使用 redux 以後你就不能直接調用組件的方法了, 好比你寫個彈窗有個 show() 方法, 你在使用的地方經過引用 this.xxxDialog.show()是不會起做用的, 須要嚴格遵照單向數據流的思想. 儘管它有一些特性能夠支持這麼作(好比先將子組件的值傳遞給父組件,而後再由父組件在分發給指定的子組件)。這被不少人認爲是糟糕的實踐方式,由於這樣的方式容易出錯並且會讓代碼向「拉麪」同樣不容易理解。
固然React也沒有直接建議如何去處理這種情形, React 官方是這麼解釋的:設計模式

對於非父子關係的組件,你能夠本身創建一個全局的事件系統,Flux的模式也是一種可行的方式。app

Redux的出現就讓這個問題的解決變得更加方便了。異步

Redux提供一種存儲整個應用狀態到一個地方的解決方案(能夠理解爲統一狀態層),這個存儲全部應用狀態的地方稱爲「store」,組件發生事件時不會再 setState, 而是由 store 分發(dispatch)一個事件(action),  組件將狀態的變化通知給store,而不是直接通知其它的組件, store會根據 action 的類型來調用對應的 reducer(純函數, 告訴 state 該作出什麼變化), reducer 會根據 action 的類型, 接收一箇舊的 state, 返回一個新的 state,  store 會收集到全部 reducer的state, 最後更新 state,  組件內部依賴的state的變化狀況就能夠經過訂閱 store 來實現。如圖所示:ide

 

 


使用Redux,全部的組件都從store裏面獲取它們依賴的state,同時也須要將state的變化告知store。組件不須要關注在這個store裏面其它組件的state的變化狀況,Redux讓數據流變得更加簡單。這種思想最初來自Flux,它是一種和React相同的單向數據流的設計模式。

若是你的頁面單一頁面, 功能簡單, 狀態很少變, 沒有涉及多個頁面之間的交互, 那麼你就不用往下看了, 你真的不須要用 redux這麼重量級的東西, 可是好比作多語言, 換膚功能, 字體切換也能夠考慮用redux.

 

redux 的三原則

1. Single source of truth
單一數據源。整個應用的state,存儲在惟一一個object中, 那就是 store, 一個應用有且只有一個 store

2. State is read-only 
狀態是隻讀的。惟一能改變state的方法,就是觸發action操做。不要想着再去 setState 了, 用了 redux 以後你改變 state 惟一的方法就是 dispatch 一個 action, action是什麼? 別急,下面再說

3.  Changes are made with pure functions
在改變state tree時,用到action,同時也須要編寫對應的reducers才能完成state改變操做。而且 reducer 必定要是一個純函數, 不要在裏面作一些亂七八糟的騷操做

2 >> 什麼是 Action?   reducer ?   store ? provider? 

Action  動做 :好比登陸操做  退出登陸操做 添加待辦 刪除待辦均可以定義爲一個 action

example:

 

 
 
 
 
嚴格的來說這應該叫作ActionCreactor , 他返回的那個對象才叫 action, action 就是一個純對象, 描述正在發生的事情, 也就是觸發的操做, 好比這個就是描述正在登陸的過程, 只不過我傳遞的有個 data, 裏面存的是登陸狀態, 一會再講這個data 怎麼用, 總之記住一句話, action 就是一個純對象, 描述正在發生的事件.必需要有一個 type 屬性, types 那個就是一個常量, 用來標識和區分你的 action 的類型, 好比是登陸仍是登出, 是添加仍是刪除.
 
Store 全局惟一的一個對象 能夠看做應用 state 的集合 , 也就是說你在任意組件中均可以經過 store 拿到你想要的 state

這就是一個完整的 store 的建立過程, createStore 是redux 裏提供的函數, 接受初始狀態,  reducer( reducer 能夠有多個, 這裏是合併多個 reducer 的 RootReducer ),   中間件.

store 有什麼用呢? store 就是一個保存着整個 APP 的全部state 的對象, 顧名思義, 就是一個倉庫嘛, 在任何一個組件中均可以經過store 來獲取任何一個 state,

Reducer  是一個純函數, 不要在這裏作邏輯操做的事情, 他就是根據一個 action 的 type 返回一個新的 state 必定要保證其純潔性

 異步Action

// 異步的Action 須要返回的是一個 function 在 createStore 時由middleWare 作處理 普通的action 直接返回純對象便可
  export function requireLogin(info) {
  return LoginApi(info);
  }

 

 

這其實就是一個 action(只不過是個異步的 action , 以下圖上面是一個普通的同步 action  , dispatch 這個 action 立刻就執行, 返回新的 state, UI 更新, 可是異步的不一樣, 不能立刻獲取新的 state

這裏模仿請求的百度, 請求完成登陸成功, 異步的 action 返回的不是純對象了, 而是一個函數, 就是上圖那個函數, 另外在建立 store 的時候還要使用middleware 中間件, 這樣才能執行異步操做)

 

廢話都說的差很少了, 相信你對 redux大概有個瞭解了, 起碼對 action reducer store 這三個概念有個印象, action 就是描述一件事情發生的對象, reducer 就是個純函數, 接受舊的 state 和一個 action, 返回一個新的 state 到 store, store 就是全局惟一的一個倉庫,存儲着應用全部的 state

 

Provider

provider主要有兩個功能 

  • 在原應用組件上包裹一層,使原來整個應用成爲Provider的子組件
  • 接收Redux的store做爲props,經過context對象傳遞給子孫組件上的connect

context可使子孫組件直接獲取父級組件中的數據或方法,而無需一層一層經過props向下傳遞。context對象至關於一個獨立的空間,父組件經過getChildContext()向該空間內寫值;定義了contextTypes驗證的子孫組件能夠經過this.context.xxx,從context對象中讀取xxx字段的值。

總而言之,Provider模塊的功能很簡單,從最外部封裝了整個應用,並向connect模塊傳遞store。

而最核心的功能在connect模塊中。

connect的做用:

一、connect經過context獲取Provider中的store,經過store.getState()獲取整個store tree 上全部state。
二、connect模塊的返回值wrapWithConnect爲function。
三、wrapWithConnect返回一個ReactComponent對象Connect,Connect從新render外部傳入的原組件WrappedComponent,並把connect中傳入的mapStateToProps, mapDispatchToProps與組件上原有的props合併後,經過屬性的方式傳給WrappedComponent

 

下面進入實戰

1. 建立你的項目, 新建以下文件夾

constants actions reducers store pages 

這裏說一下 不作異步請求的話 就不用像我那樣用中間件 action 返回函數, 直接return 一個對象, 只有一個 type字段就OK  項目的在 Github 上本身能夠看一下

 

 2 npm install  react-redux  redux   redux-logger(這個會打印你的全部 state和 action變化 , 建議使用)    redux-thunk(中間件, 用於異步操做)    react-navigation(若是你要作多個頁面跳轉就install)

3. 新建一個 Root.js

用 provider 包住你的 APP, 這樣全部的組件就均可以獲取到 store 的 state 變化了 注意要傳遞 store

而後就是把 Root.js 當成 App.js同樣, 放到你的 index.js裏便可

4. 接下來就是編寫 action  reducer  store 了

舉個簡單的加減的同步操做的例子

 actionCreactor: 函數返回一個 action

 reducer:

這裏要提一下, reducer 能夠有不少個, 拆分 reducer 對一個不一樣的操做, 而後用combineReducers 合併全部的 reducer 到 rootReducer, 以下圖:

我我的習慣叫 xxxReducer , 在組件中使用的時候, 能夠 state.xxxReducer.xxx 便於區分

 

5. 在 page裏怎麼使用 

example登陸的操做

下面登陸就這麼簡單了只須要一句 this.props.loginAction() , 登陸的邏輯在 loginRequest 裏, 發起登陸操做便可, 也算能夠給 page解耦, 

 

 

 

這裏要注意一下 bindActionCreactors 他的做用是把 dispatch 函數無感知的傳遞給子組件, 在子組件裏就能夠 dispatch 一個 action, 固然你也能夠經過 props 把dispatch 函數傳遞給子組件, 只是不優雅, 該函數接受兩個參數, 第一個參數能夠是函數或者對象,通常是一個 actionCreactor, 返回的也是一個函數或者對象, 第二個參數是 dispatch,

bindAction: {login_doing: ƒ, login_done: ƒ, login_err: ƒ, login_out: ƒ, requireLogin: ƒ}
* {
addTodo : text => dispatch(addTodo('text'));
removeTodo : id => dispatch(removeTodo('id'));
}
至關於 dispath 一個 action
 

這裏有個 connect 函數 他的做用就是把當前組件和 store 鏈接, 而後就能夠獲取 store 裏的 state, store 中的 state 在 dispatch一個 action 以後, 在 reducer 的做用下產生新的 state 返回到 store, 這時你的組件也能接收到新的 state, 不過是以 props 的形式, 如上 connect 函數接受兩個參數, 第一個參數接受兩個參數分別是 mapStateToProps (名字就表示了他的意思, 你須要獲取的 state 會經過props 的形式傳遞到你的當前組件) matchDispatchToProps 這個是你須要的dispatch 的 action , 我更喜歡直接在發生事件的時候去this.props.dispatch(action),  固然這種不規範, 大家仍是用matchDispatchToProps 而後就能直接 this.props.loginAction()就 OK 了

 

這個是那個簡單的同步操做加減的, count就是那個 state, 這裏已經經過 mapStateToProps 獲取了, 因此使用的時候就能夠this.props.count , 當你 dispatch一個 action 的時候, reducer 會改變他的值, 返回到 store , 最後經過 connect, store 會把這個改變後的 state 更新到這裏

 

 

 

固然在其餘地方也能夠dispatch 這個 action, 這裏的 count 也會變化, 固然在其餘地方也能夠獲取到這個 count, 這就是他的強大之處, 任何地方都能獲取到 store 中存儲的 全部的state, 在任何地方均可以 dispatch 一個你想要 dispatch 的 action, 能夠跨組件的操做和數據傳遞提供了很大的便利性和可維護性, 因此這也是他適用於邏輯複雜的應用的緣由 

 下面附上那個 redux-logger 的日誌 裏面有store 裏詳細的 state 變化  以及發起的每個 action 因此說對於解決 bug 調試起來很省事

 

是否是一目瞭然, 你觸發了哪一個 action , 改變了什麼狀態以及最終的狀態, 傳遞的數據都清晰明瞭,

總結一下吧, redux 很強大, 也很易用, 下面是一個流程圖

store 就是倉庫

action 就是描述事件發生的對象

reducer 就是事件發生以後如何改變state 的一個純函數

相關文章
相關標籤/搜索