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的目录结构:
(如果你之前不了解Redux的话,或许会比较蒙圈,但不要紧,跟着流程多走几遍,试着推敲先分析下流程,慢慢就理解了)
/*************************************store*************************************/
1.首先创建全局的store。(一般在stores文件中写个配置文件)
- 'use strict';
- import { createStore, applyMiddleware ,combineReducers} from 'redux';
- import thunk from 'redux-thunk';//引入异步操作
- //引入所有的reducers,切记要在index.js封装下.
- import * as reducers from '../reducers';
- const middlewares = [thunk];
- const createSoreWithMiddleware=applyMiddleware(...middlewares)(createStore);
- //配置store信息
- export default function configureStore(initialState){
- //将reducer组合起来
- const reducer=combineReducers(reducers);
- //创建store
- const store=createSoreWithMiddleware(reducer,initialState);
- return store;
- }
简单讲解下:
首先引入该APP中所有的reducer,根据上面的目录结构,我们把所有的reducer放入到reducers文件中,切记要加入个index.js进行配置.上面很多都是固定格式,暂时先不分析为什么,做的目的就是返回一个全局的store.
store的应用(这里的APP就是我们应用的最顶层组件)。
- import React, { Component } from 'react';
- import {Provider} from 'react-redux';
- import App from './containers/app';
- import configureStore from './store/configureStore';
- const store=configureStore();//获取store
- export default class Root extends Component{
- render(){
- return(
- <Provider store={store}>
- <App/>
- </Provider>
- );
- }
- }
App组件其实可以把所有的页面加入到这里,全局进行控制(官方F8是这么操作的)。不过这里暂时先不这样处理,关于navigator的push,pop操作还是放到对应的页面进行处理,更符合我们的原生开发逻辑。
简单看下store中结构:
/*************************************action*************************************/
创建登陆对应的action:
- import * as types from './types';
- import {Alert}from 'react-native';
- //登陆(登陆操作属于耗时操作,所以需要异步执行,这里采用dispatch分发)
- export function login(user){
- return dispatch=>{
- //登陆中,派遣给LOGIN_ING
- dispatch({type:types.LOGIN_ING});
- let result=fetch('http://www.baidu.com')
- .then((res)=>{
- //延时2s为了模拟效果
- setTimeout(()=>{
- if(user.phone=='15221850400'&&user.password=='123456'){
- dispatch({type:types.LOGIN,user:user});
- }else{
- //这里分发的是action
- Alert.alert('用户名或密码错误');
- dispatch(error());
- }
- },1000);
- }).catch((err)=>{
- alert(err);
- dispatch({type:types.LOGIN_ERROR});
- })
- }
- }
- function error(){
- return {
- type:types.LOGIN_ERROR
- };
- }
- //登出(由于登出操作一般都只是清空一些数据,不需要异步执行直接返回就可以了,)
- export function logout(){
- return {
- type:types.LOGOUT,
- };
- }
逻辑还算简单,就只是做个用户名,密码判断,但或许会问dispatch是个什么玩意,哪来的呢,其实上面我们也截图出来了,这个方法是我们创建全局store中的方法。
至于action正常的应该只是一个含有type的json对象,但是为了扩展性,一般会写成函数的形式,俗称action creator如上面的logout方法.
至于login方法由于需要网络操作,固然是异步的,就好比我们原生开发的时候请求API的操作一般都会丢到一个线程中,通过Handler消息机制来渲染UI.
dispatch({type:types.LOGIN_ING}):根据相应的action来进行调用对应reducer方法。
/*************************************reducer*************************************/
接着我们看下最后一个reducer:
- import * as types from '../actions/types';
- const initialState={
- isLoggedIn:false,//登陆状态
- user:{},
- status: null,//登陆操作状态 ‘done’:已登陆,'doing':正在登陆,null:没有登陆
- };
- //reducer处理函数更新state,渲染UI(主要根据传入旧的state,)
- export default function user(state=initialState,action={}){
- switch(action.type) {
- case types.LOGIN:
- return{
- ...state,
- isLoggedIn:true,
- user:action.user,
- status: 'done',
- }
- break;
- case types.LOGIN_ING:
- return {
- ...state,
- isLoggedIn:false,
- status: 'doing',
- }
- break;
- case types.LOGIN_ERROR:
- console.log('types.LOGIN_ERROR...');
- return{
- ...state,
- isLoggedIn: false,
- status: null,
- };
- break;
- case types.LOGOUT:
- return {
- ...state,
- isLoggedIn:false,
- status:null,
- }
- break;
- //切莫忘记default返回值
- default:
- return state;
- }
- }
reducer其实就是根据一系列action的处理函数,好比我们在前面action中返回的有LOGIN,LOGIN_ING,LOGIN_ERROR等状态,然后调用reducer根据不同的type返回当前最新的state,然后再render ui。
/*************************************connect*************************************/
redux的三部分至此就操作完毕,但如果进行链接起来呢,这里就用到connect组件,connect是将某一个组件(这里一般指一个页面)和store链接起来,目的就是获取当前页面所需的state以及dispatch方法。(从全局state中获取这个页面需要的数据然后以props的形式传递给当前页面。)
- import React, { Component } from 'react';
- import {
- StyleSheet,
- TextInput,
- Text,
- View,
- TouchableHighlight,
- ActivityIndicator,
- } from 'react-native';
- import {connect} from 'react-redux';//将我们的页面和action链接起来
- import {bindActionCreators} from 'redux';//将要绑定的actions和dispatch绑定到一起
- import * as actionCreators from '../actions/loginActions';//导入需要绑定的actions
- import Modal from 'react-native-modalbox';
- import Home from './home';
- /**
- 登陆页面
- **/
- class Login extends Component{
- constructor(props){
- super(props);
- this.state={
- }
- this.login=this.login.bind(this);
- this.onChangePhone=this.onChangePhone.bind(this);
- this.onChangePswd=this.onChangePswd.bind(this);
- }
- onChangePhone(text){
- this.setState({'phone':text,});
- }
- onChangePswd(text){
- this.setState({'password':text,});
- }
- login(){
- if(!this.state.phone||!this.state.password){
- alert('用户名或密码不能为空!');
- }else{
- this.refs.modal.open();//loading 状态
- this.props.actions.login({'phone':this.state.phone,'password':this.state.password});//dispath 登陆
- }
- }
- //该方法首次不会执行,如果返回false,则reduer不会执行,,
- shouldComponentUpdate(nextProps,nextState){
- const {isLoggedIn,navigator}=nextProps;
- if(isLoggedIn){
- this.setState({phone:'',password:''});
- navigator.push({
- component:Home,
- name:'Home',
- });
- }
- return true;
- }
- render(){
- console.log('render...');
- return(
- <View style={{flex:1}}>
- <View style={{padding:20,marginTop:50}}>
- <View style={styles.item}><Text style={{width:70}}>手机号码</Text>
- <TextInput
- style={styles.input}
- onChangeText={this.onChangePhone}
- placeholder='请输入手机号码'
- value={this.state.phone}
- />
- </View>
- <View style={styles.item}>
- <Text style={{width:70}}>密码</Text>
- <TextInput
- style={styles.input}
- onChangeText={this.onChangePswd}
- placeholder='请输入密码'
- password={true}
- value={this.state.password}
- />
- </View>
- <TouchableHighlight style={styles.button}
- underlayColor='#000000' onPress={this.login}>
- <Text style={{fontSize:16,color:'#fff'}}>登陆</Text>
- </TouchableHighlight>
- </View>
- <Modal
- style={styles.modal}
- ref='modal'
- isOpen={this.props.status=='doing'?true:false}
- animationDuration={0}
- position={"center"}
- >
- <ActivityIndicator
- size='large'
- />
- <Text style={{marginTop:15,fontSize:16,color:'#444444'}}>登陆中...</Text>
- </Modal>
- </View>
- );
- }
- }
- const styles =StyleSheet.create({
- item:{
- flex:1,
- flexDirection:'row',
- alignItems:'center',
- height:50,
- borderBottomColor:'#ddd',
- borderBottomWidth:1,
- },
- input:{
- flex:1,
- fontSize:14,
- },
- button:{
- backgroundColor:'#1a191f',
- height:50,
- marginTop:40,
- justifyContent:'center',
- alignItems:'center'
- },
- modal: {
- justifyContent: 'center',
- alignItems: 'center',
- width:150,
- height:150,
- borderRadius:10,
- },
- });
- //根据全局state返回当前页面所需要的信息,(注意以props的形式传递给Login)
- function mapStateToProps(state){
- return{
- isLoggedIn:state.user.isLoggedIn,
- status:state.user.status,
- };
- }
- //返回可以操作store.state的actions,(其实就是我们可以通过actions来调用我们绑定好的一系列方法)
- function mapDispatchToProps(dispatch){
- return {
- actions: bindActionCreators(actionCreators, dispatch)
- };
- }
- //链接起来
- 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
写博客是为了记住自己容易忘记的东西,另外也是对自己工作的总结,文章可以转载,无需版权。希望尽自己的努力,做到更好,大家一起努力进步!
如果有什么问题,欢迎大家一起探讨,代码如有问题,欢迎各位大神指正!
React Native集成Redux框架讲解与应用的更多相关文章
- Angular团队公布路线图,并演示怎样与React Native集成
本文来源于我在InfoQ中文站翻译的文章,原文地址是:http://www.infoq.com/cn/news/2015/06/angular-2-react-native-roadmap 前不久在旧 ...
- 将React Native集成至Android原生应用
将React Native集成至Android原生应用 Android Studio 2.1 Preview 4生成的空项目 react-native 环境 0.22.2 初次编译后apk有1.1M, ...
- [RN] React Native 使用 Redux 比较详细和深刻的教程
React Native 使用 Redux 比较详细和深刻的教程 React Native 使用 Redux https://www.jianshu.com/p/06fc18cef56a http:/ ...
- 一次掌握 React 与 React Native 两个框架
此系列文章将整合我的 React 视频教程与 React Native 书籍中的精华部分,给大家介绍 React 与 React Native 结合学习的方法. 1. 软件开发语言与框架的学习本质 我 ...
- 将React Native 集成进现有OC项目中(过程记录) 、jsCodeLocation 生成方式总结
将RN集成到现有OC项目应该是最常见的,特别是已经有OC项目的,不太可能会去专门搞个纯RN的项目.又因为RN不同版本,引用的依赖可能不尽相同,所以特别说明下,本文参考的文档是React Native ...
- react native 之 redux 使用套路
redux是什么?他是一个state容器 redux的运作方式是怎样的? 接入方式: 1. npm install 下列内容: npm install --save redux npm install ...
- react native 之 redux
第一章 认识redux 说的通俗且直白一点呢,就是redux提供了一个store,独立的一个内存区,然后放了一些state,你可以在任何component中访问到state,这些state要更改怎么 ...
- react native 集成react navigation报错
集成后出现:“Invalid escape sequence at line 1 column 29 path $[0].name”的错误. 解决办法:
- React Native使用Redux总结
1>npm安装redux: "react-redux": "^5.0.5", "redux": "^3.7.1", ...
随机推荐
- Jmeter_远程启动 I
Jmeter 是Java 应用,对于CPU和内存的消耗比较大,因此,当需要模拟数以千计的并发用户时,使用单台机器模拟所有的并发用户就有些力不从心,甚至会引起JAVA内存溢出错误. 其实,Jmeter的 ...
- 编写高质量代码--改善python程序的建议(三)
原文发表在我的博客主页,转载请注明出处! 建议十三:警惕eval()的安全漏洞 相信经常处理文本数据的同学对eval()一定是欲罢不能,他的使用非常简单: eval("1+1==2" ...
- ThinkPHP中通过URL重写隐藏应用的入口文件index.php的相关服务器的配置
[ Apache ] 将httpd.conf配置文件中mod_rewrite.so所在行前面的‘#’去掉 AllowOverride None 将None改为 All 效果图
- Golang Frameworks
Web frameworks help developers build applications as easily and quickly as possible. Go is still rel ...
- SQL-修改: 将日期修改为空NULL、修改为空的记录
1.将日期修改为空NULL update 表 set 字段=null where 字段='' 如果设置为‘’,会默认1900-01-01 2.修改为空的记录 update [dbo].[pub_ite ...
- 巨蟒python全栈开发flask5
1.轮询&&长轮询&&长连接 2.GeventWebsocket 3.Websocket群聊 4.Websocket单聊 5.websocket握手 6.websock ...
- Group By 与 Count
select UserID,COUNT(0) From [Order] a Group By UserID UserID (无列名)1 5 2 ...
- 翻页bug 在接口文档中应规范参数的取值区间
<?php$a=array("red","green","blue","yellow","brown&q ...
- IO流入门-第一章-FileInputStream
FileInputStreamj基本用法和方法示例 import java.io.*; public class FileInputStreamTest01 { public static void ...
- 第04章—整合Mybatis
spring boot 系列学习记录:http://www.cnblogs.com/jinxiaohang/p/8111057.html 码云源码地址:https://gitee.com/jinxia ...