React Native集成Redux框架講解與應用

學過React Native的都知道,RN的UI是根據相應組件的state進行render的,而頁面又是由大大小小的組件構成,導致每個組件都必須維護自身的一套狀態,因此當頁面復雜化的時候,管理state會相當吃力的。而redux提供了一套機制來組織管理整個應用狀態。

? ? ? ?Redux有三部分組成:store,action,reducer。

? ? ? ?store:維護全局的state,以及將action和reducer結合起來。

? ? ? ?action:用來傳遞state的信息。(比如:我們在action中處理登陸操作,將返回的user對象傳遞給對應的reducer.)

? ? ? ?reducer:reducer是簡單的處理函數,通過傳入舊的state和指示操作的action來更新state,從而達到頁面的刷新。

下面通過一個簡單的例子來集成下。

首先安裝相關庫:

?

安裝redux:npm install --save redux

安裝redux綁定庫:npm install --save react-redux

安裝開發者工具:npm install --save-dev redux-devtools

安裝異步action構造器:npm install --save redux-thunk

在集成之前熟悉下一般基于Redux的目錄結構:

?

 
.
├── src #開發目錄
| |
| ├──constants #ActionTypes和Urls
| |
| ├──actions #actions的文件
| |
| ├──components #內部組件
| |
| ├──containers #容器組件
| |
| ├──reducers #reducer文件
| |
| ├──stores #store配置文件
| |
| └──utils #工具
|
├── node_modules #包文件夾
├── .gitignore
├── index.js #入口文件
└── package.json

(如果你之前不了解Redux的話,或許會比較蒙圈,但不要緊,跟著流程多走幾遍,試著推敲先分析下流程,慢慢就理解了)

/*************************************store*************************************/

1.首先創建全局的store。(一般在stores文件中寫個配置文件)

?

[javascript]?view plain?copy
  1. 'use?strict';??
  2. ??
  3. import?{?createStore,?applyMiddleware?,combineReducers}?from?'redux';??
  4. import?thunk?from?'redux-thunk';//引入異步操作??
  5. //引入所有的reducers,切記要在index.js封裝下.??
  6. import?*?as?reducers?from?'../reducers';??
  7. const?middlewares?=?[thunk];??
  8. ??
  9. const?createSoreWithMiddleware=applyMiddleware(...middlewares)(createStore);??
  10. ??
  11. //配置store信息??
  12. export?default?function?configureStore(initialState){??
  13. ??
  14. ??//將reducer組合起來??
  15. ??const?reducer=combineReducers(reducers);??
  16. ??//創建store??
  17. ??const?store=createSoreWithMiddleware(reducer,initialState);??
  18. ????
  19. ??return?store;??
  20. }??

簡單講解下:

首先引入該APP中所有的reducer,根據上面的目錄結構,我們把所有的reducer放入到reducers文件中,切記要加入個index.js進行配置.上面很多都是固定格式,暫時先不分析為什么,做的目的就是返回一個全局的store.

store的應用(這里的APP就是我們應用的最頂層組件)。

?

[javascript]?view plain?copy
  1. import?React,?{?Component?}?from?'react';??
  2. import?{Provider}?from?'react-redux';??
  3. import?App?from?'./containers/app';??
  4. ??
  5. import?configureStore?from?'./store/configureStore';??
  6. const?store=configureStore();//獲取store??
  7. ??
  8. export?default?class?Root?extends?Component{??
  9. ???render(){??
  10. ?????return(??
  11. ???????<Provider?store={store}>??
  12. ???????<App/>??
  13. ???????</Provider>??
  14. ?????);??
  15. ???}??
  16. }??

App組件其實可以把所有的頁面加入到這里,全局進行控制(官方F8是這么操作的)。不過這里暫時先不這樣處理,關于navigator的push,pop操作還是放到對應的頁面進行處理,更符合我們的原生開發邏輯。

簡單看下store中結構:

?

/*************************************action*************************************/

創建登陸對應的action:

?

[javascript]?view plain?copy
  1. ?import?*?as?types?from?'./types';??
  2. ?import?{Alert}from?'react-native';??
  3. ??
  4. //登陸(登陸操作屬于耗時操作,所以需要異步執行,這里采用dispatch分發)??
  5. export?function?login(user){??
  6. ???return?dispatch=>{??
  7. ?????//登陸中,派遣給LOGIN_ING??
  8. ?????dispatch({type:types.LOGIN_ING});??
  9. ?????let?result=fetch('http://www.baidu.com')??
  10. ????????????????.then((res)=>{??
  11. ??????????????????//延時2s為了模擬效果??
  12. ??????????????????setTimeout(()=>{??
  13. ????????????????????if(user.phone=='15221850400'&&user.password=='123456'){??
  14. ??????????????????????dispatch({type:types.LOGIN,user:user});??
  15. ????????????????????}else{??
  16. ??????????????????????//這里分發的是action??
  17. ??????????????????????Alert.alert('用戶名或密碼錯誤');??
  18. ??
  19. ??????????????????????dispatch(error());??
  20. ????????????????????}??
  21. ??????????????????},1000);??
  22. ????????????????}).catch((err)=>{??
  23. ???????????????????alert(err);??
  24. ???????????????????dispatch({type:types.LOGIN_ERROR});??
  25. ????????????????})??
  26. ???}??
  27. }??
  28. ??
  29. function?error(){??
  30. ??return?{??
  31. ????type:types.LOGIN_ERROR??
  32. ??};??
  33. }??
  34. ??
  35. //登出(由于登出操作一般都只是清空一些數據,不需要異步執行直接返回就可以了,)??
  36. export?function?logout(){??
  37. ??return?{??
  38. ????type:types.LOGOUT,??
  39. ??};??
  40. }??

邏輯還算簡單,就只是做個用戶名,密碼判斷,但或許會問dispatch是個什么玩意,哪來的呢,其實上面我們也截圖出來了,這個方法是我們創建全局store中的方法。

至于action正常的應該只是一個含有type的json對象,但是為了擴展性,一般會寫成函數的形式,俗稱action creator如上面的logout方法.

至于login方法由于需要網絡操作,固然是異步的,就好比我們原生開發的時候請求API的操作一般都會丟到一個線程中,通過Handler消息機制來渲染UI.

dispatch({type:types.LOGIN_ING}):根據相應的action來進行調用對應reducer方法。

/*************************************reducer*************************************/

接著我們看下最后一個reducer:

?

[javascript]?view plain?copy
  1. import?*?as?types?from?'../actions/types';??
  2. ??
  3. const?initialState={??
  4. ??isLoggedIn:false,//登陸狀態??
  5. ??user:{},??
  6. ??status:?null,//登陸操作狀態?‘done’:已登陸,'doing':正在登陸,null:沒有登陸??
  7. };??
  8. ??
  9. //reducer處理函數更新state,渲染UI(主要根據傳入舊的state,)??
  10. export?default?function?user(state=initialState,action={}){??
  11. ??
  12. ??switch(action.type)?{??
  13. ????case?types.LOGIN:??
  14. ???????return{??
  15. ?????????...state,??
  16. ?????????isLoggedIn:true,??
  17. ?????????user:action.user,??
  18. ?????????status:?'done',??
  19. ???????}??
  20. ??????break;??
  21. ????case?types.LOGIN_ING:??
  22. ??????return?{??
  23. ????????...state,??
  24. ????????isLoggedIn:false,??
  25. ????????status:?'doing',??
  26. ??????}??
  27. ??????break;??
  28. ????case?types.LOGIN_ERROR:??
  29. ????console.log('types.LOGIN_ERROR...');??
  30. ????????return{??
  31. ??????????...state,??
  32. ????????????isLoggedIn:?false,??
  33. ??????????status:?null,??
  34. ????????};??
  35. ????????break;??
  36. ????case?types.LOGOUT:??
  37. ??
  38. ??????return?{??
  39. ????????...state,??
  40. ????????isLoggedIn:false,??
  41. ????????status:null,??
  42. ??????}??
  43. ??????break;??
  44. ????//切莫忘記default返回值??
  45. ????default:??
  46. ??????return?state;??
  47. ??}??
  48. }??

reducer其實就是根據一系列action的處理函數,好比我們在前面action中返回的有LOGIN,LOGIN_ING,LOGIN_ERROR等狀態,然后調用reducer根據不同的type返回當前最新的state,然后再render ui。

/*************************************connect*************************************/

redux的三部分至此就操作完畢,但如果進行鏈接起來呢,這里就用到connect組件,connect是將某一個組件(這里一般指一個頁面)和store鏈接起來,目的就是獲取當前頁面所需的state以及dispatch方法。(從全局state中獲取這個頁面需要的數據然后以props的形式傳遞給當前頁面。)

?

[javascript]?view plain?copy
  1. import?React,?{?Component?}?from?'react';??
  2. import?{??
  3. ??StyleSheet,??
  4. ??TextInput,??
  5. ??Text,??
  6. ??View,??
  7. ??TouchableHighlight,??
  8. ??ActivityIndicator,??
  9. }?from?'react-native';??
  10. ??
  11. import?{connect}?from?'react-redux';//將我們的頁面和action鏈接起來??
  12. import?{bindActionCreators}?from?'redux';//將要綁定的actions和dispatch綁定到一起??
  13. import?*?as?actionCreators?from?'../actions/loginActions';//導入需要綁定的actions??
  14. import?Modal?from?'react-native-modalbox';??
  15. import?Home?from?'./home';??
  16. ??
  17. ??
  18. /**?
  19. 登陸頁面?
  20. **/??
  21. class?Login?extends?Component{??
  22. ??
  23. ??constructor(props){??
  24. ????super(props);??
  25. ??
  26. ????this.state={??
  27. ????}??
  28. ??
  29. ????this.login=this.login.bind(this);??
  30. ????this.onChangePhone=this.onChangePhone.bind(this);??
  31. ????this.onChangePswd=this.onChangePswd.bind(this);??
  32. ??}??
  33. ??
  34. ???onChangePhone(text){??
  35. ?????this.setState({'phone':text,});??
  36. ???}??
  37. ??
  38. ???onChangePswd(text){??
  39. ?????this.setState({'password':text,});??
  40. ???}??
  41. ??
  42. ???login(){??
  43. ??
  44. ?????if(!this.state.phone||!this.state.password){??
  45. ???????alert('用戶名或密碼不能為空!');??
  46. ?????}else{??
  47. ???????this.refs.modal.open();//loading?狀態??
  48. ???????this.props.actions.login({'phone':this.state.phone,'password':this.state.password});//dispath?登陸??
  49. ?????}??
  50. ???}??
  51. ??
  52. ???//該方法首次不會執行,如果返回false,則reduer不會執行,,??
  53. ???shouldComponentUpdate(nextProps,nextState){??
  54. ?????const?{isLoggedIn,navigator}=nextProps;??
  55. ??????if(isLoggedIn){??
  56. ????????this.setState({phone:'',password:''});??
  57. ??
  58. ????????navigator.push({??
  59. ??????????component:Home,??
  60. ??????????name:'Home',??
  61. ????????});??
  62. ??????}??
  63. ?????return?true;??
  64. ???}??
  65. ??
  66. ???render(){??
  67. ????console.log('render...');??
  68. ?????return(??
  69. ??????<View?style={{flex:1}}>??
  70. ??????<View?style={{padding:20,marginTop:50}}>??
  71. ??????<View?style={styles.item}><Text?style={{width:70}}>手機號碼</Text>??
  72. ??????<TextInput??
  73. ??????style={styles.input}??
  74. ??????onChangeText={this.onChangePhone}??
  75. ??????placeholder='請輸入手機號碼'??
  76. ??????value={this.state.phone}??
  77. ??????/>??
  78. ??????</View>??
  79. ??????<View?style={styles.item}>??
  80. ??????<Text?style={{width:70}}>密碼</Text>??
  81. ??????<TextInput??
  82. ??????style={styles.input}??
  83. ??????onChangeText={this.onChangePswd}??
  84. ??????placeholder='請輸入密碼'??
  85. ??????password={true}??
  86. ??????value={this.state.password}??
  87. ??????/>??
  88. ??????</View>??
  89. ??
  90. ??????<TouchableHighlight?style={styles.button}??
  91. ???????underlayColor='#000000'?onPress={this.login}>??
  92. ??????<Text?style={{fontSize:16,color:'#fff'}}>登陸</Text>??
  93. ??????</TouchableHighlight>??
  94. ??????</View>??
  95. ??
  96. ??????<Modal??
  97. ??????style={styles.modal}??
  98. ??????ref='modal'??
  99. ??????isOpen={this.props.status=='doing'?true:false}??
  100. ??????animationDuration={0}??
  101. ??????position={"center"}??
  102. ??????>??
  103. ??????<ActivityIndicator??
  104. ??????size='large'??
  105. ??????/>??
  106. ??????<Text?style={{marginTop:15,fontSize:16,color:'#444444'}}>登陸中...</Text>??
  107. ??????</Modal>??
  108. ??????</View>??
  109. ?????);??
  110. ???}??
  111. }??
  112. ??
  113. const?styles?=StyleSheet.create({??
  114. ????item:{??
  115. ??????flex:1,??
  116. ??????flexDirection:'row',??
  117. ??????alignItems:'center',??
  118. ??????height:50,??
  119. ??????borderBottomColor:'#ddd',??
  120. ??????borderBottomWidth:1,??
  121. ????},??
  122. ????input:{??
  123. ??????flex:1,??
  124. ??????fontSize:14,??
  125. ????},??
  126. ????button:{??
  127. ??????backgroundColor:'#1a191f',??
  128. ??????height:50,??
  129. ??????marginTop:40,??
  130. ??????justifyContent:'center',??
  131. ??????alignItems:'center'??
  132. ????},??
  133. ????modal:?{??
  134. ??????justifyContent:?'center',??
  135. ??????alignItems:?'center',??
  136. ??????width:150,??
  137. ??????height:150,??
  138. ??????borderRadius:10,??
  139. ????},??
  140. });??
  141. ??
  142. //根據全局state返回當前頁面所需要的信息,(注意以props的形式傳遞給Login)??
  143. function?mapStateToProps(state){??
  144. ??return{??
  145. ????isLoggedIn:state.user.isLoggedIn,??
  146. ????status:state.user.status,??
  147. ??};??
  148. }??
  149. //返回可以操作store.state的actions,(其實就是我們可以通過actions來調用我們綁定好的一系列方法)??
  150. function?mapDispatchToProps(dispatch){??
  151. ??return?{??
  152. ??????actions:?bindActionCreators(actionCreators,?dispatch)??
  153. ??};??
  154. }??
  155. ??
  156. //鏈接起來??
  157. export?default?connect(mapStateToProps,mapDispatchToProps)(Login);??

上面的代碼不用仔細看,主要是尾部的部分,

mapStateToProps方法:根據全局state返回當前頁面所需的數據然后以props的形式傳遞給當前頁面(Login)。

mapDispatchToProps:該方法就是將dispatch和當前頁面引入的actionCreators綁定在一起,然后就可以輕松調用。

如:login方法中的:

this.props.actions.login({'phone':this.state.phone,'password':this.state.password});//dispath 登陸

?

這樣整體集成就完畢了,這里簡單總結下:

1.首先我們創建全局的store(基于所有的reducer)在APP最外層引用,然后我們創建action(可以根據頁面或者某種類別來定義)。接著我們創建reducer(可以設計成跟action一一對應)。最后通過connect將它們和頁面鏈接起來,至于action和reducer的內容,可以等頁面編輯OK后再進行設計。

2.執行簡單流程:在頁面中首先調用對應action方法(傳遞參數)--->執行相應的業務邏輯,然后調用dispatch(action)(將結果以action的形式傳遞給reducer)--->在reducer中根據type字段然后返回最新的state,然后在進行render具體的ui。

?

引用原文:https://blog.csdn.net/jj120522/article/details/52071469

可以參考:https://www.jianshu.com/p/4139babc6d5e

?

寫博客是為了記住自己容易忘記的東西,另外也是對自己工作的總結,文章可以轉載,無需版權。希望盡自己的努力,做到更好,大家一起努力進步!

如果有什么問題,歡迎大家一起探討,代碼如有問題,歡迎各位大神指正!

轉載于:https://www.cnblogs.com/summary-2017/p/8626414.html

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/452258.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/452258.shtml
英文地址,請注明出處:http://en.pswp.cn/news/452258.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

【筆試記錄】2021/3/10阿里

阿里20210310春招筆試記錄-Python解題 第一題 問題描述&#xff1a; 小偷從出發點按指定方向出發&#xff0c;除非遇到墻或超出城市必須轉方向&#xff0c;不然只能直走。城市大小m*n。輸入描述&#xff1a; 1. 第1行&#xff0c;三個數字m n k&#xff1b;m*n表示城市大小&…

Spring mvc中@RequestMapping 6個基本用法小結

前些天發現了一個巨牛的人工智能學習網站&#xff0c;通俗易懂&#xff0c;風趣幽默&#xff0c;忍不住分享一下給大家。點擊跳轉到教程。 小結下spring mvc中的RequestMapping的用法。 1&#xff09;最基本的&#xff0c;方法級別上應用&#xff0c;例如&#xff1a; …

學成在線--7.CMS頁面管理開發(異常處理)

文章目錄1.異常處理的問題分析2.異常處理流程3.可預知異常處理1.自定義異常類2.異常拋出類3.異常捕獲類4.異常處理測試1&#xff09;定義錯誤代碼2&#xff09;異常處理測試4.不可預知異常處理1.定義異常捕獲方法1&#xff09;異常拋出測試2&#xff09;異常捕獲方法1.異常處理…

函數重載與運算符重載

有兩種重載&#xff1a;函數重載是指在同一作用域內的若干個參數特征不同的函數可以使用相同的函數名字&#xff1b;運算符重載是指同一個運算符可以施加于不同類型的操作數上面。就是對已有的運算符重新進行定義&#xff0c;賦予其另一種功能&#xff0c;以適應不同的數據類型…

Django(6)

為什么不用_set related_name和related_query_name的區別related_name將成為相關對象的屬性&#xff0c;允許您使用外鍵對模型進行“倒退”。例如&#xff0c;如果ModelA有像下面這樣的字段&#xff0c;那么model_b ForeignKeyField(ModelB, related_namemodel_as)這將使您能夠…

P5 RV1126編碼測試Demo

目錄 前言 01 測試Demo大致流程圖 02 代碼分析 2.1 VI設備初始化 2.2 使能通道 —— RK_MPI_VI_EnableChn 2.3 VI 和 VENC綁定 2.4 創建 編碼線程 前言 從本章開始我們將要學習嵌入式音視頻的學習了 &#xff0c;使用的瑞芯微的開發板 &#x1f3ac; 個人主頁&#xff1a…

MP算法和OMP算法及其思想

主要介紹MP(Matching Pursuits)算法和OMP(Orthogonal Matching Pursuit)算法[1]&#xff0c;這兩個算法雖然在90年代初就提出來了&#xff0c;但作為經典的算法&#xff0c;國內文獻(可能有我沒有搜索到)都僅描述了算法步驟和簡單的應用&#xff0c;并未對其進行詳盡的分析&…

【牛客刷題記錄】2021-03-10

牛客代碼刷題記錄1 問題一 給定一個數組序列, 需要求選出一個區間, 使得該區間是所有區間中經過如下計算的值最大的一個&#xff1a; 區間中的最小數 * 區間所有數的和最后程序輸出經過計算后的最大值即可&#xff0c;不需要輸出具體的區間。如給定序列 [6 2 1]則根據上述公式…

SpringMVC詳細示例實戰教程

一、SpringMVC基礎入門&#xff0c;創建一個HelloWorld程序 1.首先&#xff0c;導入SpringMVC需要的jar包。 2.添加Web.xml配置文件中關于SpringMVC的配置 123456789101112131415<!--configure the setting of springmvcDispatcherServlet and configure the mapping-->&…

學成在線--8.Freemarker入門教程

文章目錄1.FreeMarker介紹1&#xff09;常用的java模板引擎還有哪些&#xff1f;2&#xff09;freemarker是一個用Java開發的模板引擎3&#xff09;模板數據模型輸出2.FreeMarker快速入門1&#xff09;創建測試工程2&#xff09;配置文件3&#xff09;創建模型類4&#xff09;創…

面向對象建模

用面向對象方法開發軟件&#xff0c;通常需要建立3種形式的模型&#xff0c;它們分別是 描述系統數據結構的對象模型 &#xff0c; 描述系統控制結構的動態模型 和 描述系統功能的功能模型 。一個典型的軟件系統使用數據結構(對象模型)&#xff0c;執行操作(動態模型)&#xff…

if...elif...else...fi和case...esac的腳本條件判斷式

注意1&#xff1a; if 表達式和case 表達式的區別及什么時候使用哪個要有明確的區分&#xff1f; 『 if .... then .... fi 』對于變量的判斷是以『比對』的方式來分辨的&#xff0c; 如果符合狀態就進行某些行為&#xff0c;并且透過較多層次 (就是elif ) 的方式來進行多個變量…

安卓自定義View進階-分類與流程

自定義View繪制流程函數調用鏈(簡化版) 一.自定義View分類 我將自定義View分為了兩類(sloop個人分類法&#xff0c;非官方)&#xff1a; 1.自定義ViewGroup 自定義ViewGroup一般是利用現有的組件根據特定的布局方式來組成新的組件&#xff0c;大多繼承自ViewGroup或各種Layout&…

【筆試記錄】2021/3/13美團

2021/3/13美團筆試 1.旋轉二維數組 m, n map(int, input().split()) a [] for _ in range(m):a.append(list(map(int, input().split()))) for j in range(n):for k in range(m):print(a[k][j], end )print(end\n)輸入輸出 2.找出輸入字符串中的所有數字 s input() n …

Ubuntu品牌機批量涌入世界市場,中國不會例外

根據種種信息來源&#xff0c;我們可以預見&#xff1a; Ubuntu 品牌機不久即將涌入世界市場&#xff0c;中國也不會例外。對此現象&#xff0c;我們必須有一定的思想準備。 2004年4月&#xff0c;在澳大利亞一次學術會議上萌發了Ubuntu發行版的念頭&#xff0c;至今已經有8個年…

學成在線--9.頁面靜態化

文章目錄一.頁面靜態化流程二.數據模型1.輪播圖DataUrl接口1&#xff09;需求分析2&#xff09;接口定義3&#xff09;Dao4&#xff09;Service5&#xff09;Controller6&#xff09;測試2.遠程請求接口1&#xff09;添加依賴2&#xff09;配置RestTemplate3&#xff09;測試Re…

數據庫的完整性和安全性

數據的完整性防止數據庫中存在不符合語義的數據&#xff0c;也就是防止數據庫中存在不正確的數據防范對象&#xff1a;不合語義的、不正確的數據數據的安全性保護數據庫 防止惡意的破壞和非法的存取防范對象&#xff1a;非法用戶和非法操作

數據庫MySQL/mariadb知識點——日志記錄(2)二進制日志

二進制日志 記錄已提交事務導致數據改變或潛在導致數據改變的SQL語句&#xff0c;通過“重放”日志文件中的事件來生成數據副本&#xff0c;不依賴存儲引擎類型。 開啟二進制日志&#xff0c;默認是關閉的&#xff0c;二進制日志和數據分開存放 開啟記錄二進制文件的功能&#…

【面試記錄】Python常見面試200題及答案總結

Python常見面試200題及答案總結 /待完善/ 1. 列出5個常用python標準庫&#xff1f; os&#xff1a;提供了不少與操作系統相關聯的函數&#xff0c;提供了一種可移植的使用操作系統功能的方法。使用os模塊中提供的接口&#xff0c;可實現跨平臺訪問。但是&#xff0c;并不是所…

Linux負載均衡軟件LVS之一(概念篇)

2019獨角獸企業重金招聘Python工程師標準>>> 一、 LVS簡介 LVS是Linux Virtual Server的簡稱&#xff0c;也就是Linux虛擬服務器, 是一個由章文嵩博士發起的自由軟件項目&#xff0c;它的官方站點是www.linuxvirtualserver.org。現在LVS已經是 Linux標準內核的一部分…