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.mzph.cn/news/452258.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

学成在线--7.CMS页面管理开发(异常处理)

文章目录1.异常处理的问题分析2.异常处理流程3.可预知异常处理1.自定义异常类2.异常抛出类3.异常捕获类4.异常处理测试1&#xff09;定义错误代码2&#xff09;异常处理测试4.不可预知异常处理1.定义异常捕获方法1&#xff09;异常抛出测试2&#xff09;异常捕获方法1.异常处理…

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;并未对其进行详尽的分析&…

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;创…

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 …

学成在线--9.页面静态化

文章目录一.页面静态化流程二.数据模型1.轮播图DataUrl接口1&#xff09;需求分析2&#xff09;接口定义3&#xff09;Dao4&#xff09;Service5&#xff09;Controller6&#xff09;测试2.远程请求接口1&#xff09;添加依赖2&#xff09;配置RestTemplate3&#xff09;测试Re…

数据库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标准内核的一部分…

学成在线--10.页面预览

文章目录一.需求分析二. 搭建环境1.在cms服务中集成freemarker&#xff1a;2.在application.yml配置freemarker三.Service四.Controller五.页面预览测试-- 配置Nginx代理六.页面预览测试-- 添加“页面预览”链接一.需求分析 页面在发布前增加页面预览的步骤&#xff0c;方便用…

【代码刷题】排序算法总结(python实现)

排序算法总结&#xff08;Python实现&#xff09;算法介绍算法分类相关概念1. 冒泡排序&#xff08;Bubble Sort&#xff09;1.1 思想1.2 python实现1.3 复杂度1.4 稳定性2. 快速排序&#xff08;Quick Sort&#xff09;2.1 思想&#xff08;伪代码&#xff09;2.2 python实现2…

学成在线--11.RabbitMQ快速入门

文章目录一.RabbitMQ简介二.相关知识1.AMQP2.JMS是什么 &#xff1f;三.RabbitMQ的工作原理四.Hello World1.创建Maven工程2.生产者3.消费者五.总结一.RabbitMQ简介 MQ全称为Message Queue&#xff0c;即消息队列&#xff0c; RabbitMQ是由erlang语言开发&#xff0c;基于AMQP…

maven工程建立和SSM(springMVC+spring+mybatis)整合

前些天发现了一个巨牛的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;忍不住分享一下给大家。点击跳转到教程。 1.环境&#xff1a; maven 版本&#xff1a;3.5.1 ecelipse mars.2 JDK : jdk1.8.0_45 tomcat : apache-tomcat-8.0.0-RC1 2. 建…

Java——网络编程(实现基于命令行的多人聊天室)

2019独角兽企业重金招聘Python工程师标准>>> 目录&#xff1a; 1.ISO和TCP/IP分层模型 2.IP协议 3.TCP/UDP协议 4.基于TCP的网络编程 5.基于UDP的网络编程 6.基于TCP的多线程的聊天室的实现 1.ISO和TCP/IP分层模型&#xff1a; OSI分层模型&#xff08;Open System …

一网打尽中文编码转换---6种编码30个方向的转换

一网打尽中文编码转换——6种编码30个方向的转换 1.问题提出 在学编程序时&#xff0c;曾经有人问过“你可以编一个记事本程序吗?”当时很不屑一顾&#xff0c;但是随着学习MFC的深入&#xff0c;了解到记事本程序也并非易事&#xff0c;难点就是四种编码之间的转换。 对于编…

十万服务器秒级管控 腾讯云如何将AIOps用于日常管理?

AIOps&#xff0c;是指基于算法的 IT运维&#xff08;Algorithmic IT Operations&#xff09;&#xff0c;由 Gartner定义的新类别&#xff0c;源自业界之前所说的 ITOA&#xff08;IT Operations and Analytics&#xff09;。我们已经到达了这样的一个时代&#xff0c;数据科学…