ReactNative之Redux详解
用redux有一段时间了,感觉还是有必要把其相关的知识点系统的总结一下的,毕竟好记性不如烂笔头。上篇博客更新了关于《ES6中的迭代器、Generator函数以及Generator函数的异步操作》的内容,该内容时saga的基础,稍后会总结saga相关知识点。循序渐进,本篇博客主要总结的是Redux相关的内容,然后下篇博客打算总结一下react-redux, 以及redux-thunk、redux-saga中间件。
一、Redux与iOS中的Notification的比较
Redux 的功能和作用就是让State管理更为集中,因为在redux中所有的状态都是存储在Store中的,而在页面的各个模块中都可以去访问和修改Store中存储的状态值。从这一点来看,redux可以很好的解决一个页面中多个模块间的状态共享的问题。
Redux这框架理解起来是比较简单的,这个框架本身也是比较小的,涉及的API也非常少。虽然小,但小而精。使用起来还是满顺手的,大道至简。下方是Redux中的几个关键的词及对应的功能,理解完下方的几个关键词,Redux这个框架也就大概了解了。
- Store : 从字面意思看,Store是存储、储存的意思,在 Redux 中,把相关的状态存储在了Store中,在Redux中Store可以看做是一个单例对象。并且Store中提供了一些API来操作这些状态,如下所示:
- getState : 该方法用来获取Store中当前存储的状态值。
- subscribe(listener回调方法): 用来监听Store中状态值的改变,状态值改变后会执行相关回调方法。
- dispatch (action) : 该方法用来修改Store中存储的状态值,而Action就是一个普通的对象,其中可以携带一些修改特定状态时的一些信息。
- Action: 上面也说了,而Action就是一个普通的对象,其中可以携带一些修改特定状态时的一些信息,被用来作为dispatch()方法的参数的。起到了媒介的作用,Action本身会携带一些信息,便于状态的修改。
- Reducer: Reducer本质上是一个 方法集合的称呼,而这些方法的入参是 当前的State和Action,出参是被修改后的新的State对象,也就是说 dispatch 一个Action会执行一个Reducer。而Reducer对应方法,会根据Action携带的信息来修改State对象,并把修改后的State对象返回出去。当然返回这新的State会更新到Store中,从而会触发一系列的监听操作。
Redux的工作模式虽然是管理状态的,但是使用上个人感觉更想通知。与iOS中的Notification工作方式即为相似,下方做了一些简单的类比。下方简单的画了一个类比的图,可以从下往上看,解释如下:
- 通知中心:最下方是通知中心,对应着iOS的 NotificationCenter,主要用来注册、派发及移除通知的,所以的通知都会经过NotificationCenter的管理。在 Redux中,这个Store就扮演着 这个NotificationCenter的角色,用来管理所有的状态。不同的时,Store中会存储各种状态。
- 发送通知:如果要修改状态的值的话,得调用 Store中提供的 dispatch(事件派发) 方法来修改相关的状态,这个就好像 iOS中发送通知的Post方法。
- 注册监听:而Store中的 subscribe 这个监听状态改变的方法,就类似于 Notification 中的 register方法,只有添加完监听的相关对象才能收到状态被修改的通知。
- 通知对象:Store中的dispatch() 方法的参数 Action,就类似于 Notification 对象,用来携带通知或者状态修改的信息。
- 执行方法:而 redux 中的 Reducer 就类似于执行通知的Selector,用来修改状态的。
二、通过加减法示例来看Redux的使用方式
下方通过一个简单的加减法程序来看一下Redux的使用方式。之前在介绍 iOS中的响应式框架 ReactiveCocoa 时写过类似的Demo,只不过今天我们用 Redux 来实现一下。
demo比较简单,就是两个加减法,输入的时候自动的修改计算的结果值。下方我们就来简单的看一下RN中如何使用Redux来实现该功能。
1、创建Store
首先创建Store,redux 专门提供了一个创建store的方法 createStore ,调用 createStore 时,我们需要把修改State的Reducer方法传进去进行关联。下方的calculateReducer是自定义的一个修改State的方法,稍后会介绍。下方代码比较简单,就是创建了一个Store,并将该对象导了出去。
2、创建Action
创建Store后,接下来我们来创建对应的Action,下方代码就是对应的action文件中的内容。首先创建了一个 CountActionType 的对象,功能类似于枚举,其中 "ADD" 代表加法类型,"DESC" 代表减法类型。因为该示例中是在一个Reducer中处理的两个Action,所以得用 CountActionType 类型来判断派发的是哪个Action,然后做对应的操作。
然后创建了一个 addTowNumbers 方法,该方法接收了一个参数,然后返回一个Action对象,其中Action对象的类型就是 ADD。 而下方的 descTowNumbers 方法返回的也是一个Action,该Action对应的是减法操作。稍后我们会使用到该Action。
3、创建Reducer
下方的calculateReducer方法就是我们创建的Reducer, 该方法接收两个参数,一个是State对象, 一个是Action对象。我们给State对象赋了一个默认值, 这个默认值中有两个值,一个是表示加法结果的 addResult, 另一个是表示减法结果的 descResult。
Action对象中的payload对象中有两个值,及firstNumberhe和secondNumber,表示输入的两个值。而在Reducer中通过Action的Type字段来判断是做加法操作还是减法操作。如果是Add则是加法操作,将payload中的两个值相加,然后将结果赋值给 state 中的addResult。如果是Desc的话,与Add类似,只不过做的是减法操作。
在该Reducer方法中,返回的是一个计算后端新的State。State被修改后,可以通过 Store 中的 subscribe 的方法进行监听该状态的改变。
4、AddTestView的实现
定义好Store、Action、Reducer, 接下来我们就开始定义可操作的视图了。下方的AddTestView就是上面两个计算加减法的控件。下方是具体实现的说明:
在AddTestView中的构造方法中,我们调用了 store 对象中的 subscribe 方法,传入了一个回调方法,来对Store中存储的状态进行监听,然后获取state中最新的状态,然后赋值给组件对应的State对象。
第二段核心的代码则是dispathAction了,在输入框变化后,会根据是Add还是Desc调用下方的dispatchAction方法。如果是Add, 就会调用addTowNumber方法创建一个 加法动作对应的Action。如果是减法操作的话,则会调用 descTowNumber()方法创建一个减法对应的Action对象。然后把创建好的对象,通过store.dispatch(action) 方法派发出去。
store收到 Action后就会执行对应的 Reducer方法,然后去跟进Action提供的信息修改 Store中存储的State值。当State值被修改后,就会执行 subscriber 对应的回调方法获取最新的结果值,并赋值给组件内部的State对象进行展示。
下方AddTestView的全部代码。
// 仅仅使用redux
import React, { Component } from 'react';
import { Action } from 'redux';
import {Text, TouchableOpacity, View, StyleSheet, TextInput} from 'react-native';
import { store } from './store';
import {addTowNumbers, descTowNumbers, CountActionType} from './action';
const {
DESC,
ADD
} = CountActionType; type State = {
addResult: number,
descResult: number
}; const styles = StyleSheet.create({
textInput: {
width: 60,
borderRadius: 4,
borderWidth: 0.5,
borderColor: 'gray'
},
tipText: {
}
}); export default class AddTestView extends Component<null, State> {
addFirstNumber: string = '0';
addSecondNumber: string = '0';
descFirstNumber: string = '0';
descSecondNumber: string = '0'; constructor (props: any) {
super(props);
this.state = {
addResult: 0,
descResult: 0
};
store.subscribe(() => {
const {
addResult,
descResult
} = store.getState();
this.setState({ addResult, descResult });
});
} firstTextChange = (type) => (text) => {
if (type === CountActionType.ADD) {
this.addFirstNumber = text;
this.dispathAddAction();
} else {
this.descFirstNumber = text;
this.dispathDescAction();
}
} secondTextChange = (type) => (text) => {
if (type === CountActionType.ADD) {
this.addSecondNumber = text;
this.dispathAddAction();
} else {
this.descSecondNumber = text;
this.dispathDescAction();
}
} dispathAddAction = () => {
const action = addTowNumbers({firstNumber: this.addFirstNumber, secondNumber: this.addSecondNumber});
store.dispatch(action);
} dispathDescAction = () => {
const action = descTowNumbers({firstNumber: this.descFirstNumber, secondNumber: this.descSecondNumber});
store.dispatch(action);
} calculate = (type) => {
const calculateText = type === CountActionType.ADD ? '+' : '-';
const result = type === CountActionType.ADD ? this.state.addResult : this.state.descResult;
return (
<View style={{flexDirection: 'row'}}>
<TextInput style={styles.textInput} defaultValue={'0'} onChangeText = {this.firstTextChange(type)}/>
<Text> {calculateText} </Text>
<TextInput style={styles.textInput} defaultValue={'0'} onChangeText = {this.secondTextChange(type)}/>
<Text> = </Text>
<Text>{result}</Text>
</View>
);
} render () {
return (
<View style={{ justifyContent: 'center', alignItems: 'center' }}>
{this.calculate(CountActionType.ADD)}
{this.calculate(CountActionType.DESC)}
</View>
);
}
}
5、总结
介绍完相关的Demo,我们可以总结一些具体的实现流程。上述各个部分的执行过程是比较简单的,下方是具体的总结:
Component 也就是下边的AddTestView 是不会直接调用 Reducer 方法来修改状态的,而是像 Store 通过Dispatch来派发Action的方式向Store下发修改State的命令。
Store在收到 Component 派发的 Action 后会调用对应的 Reducer。
Reducer则根据提供的Action信息来修改对应的State的值,并返回给Store,更新。
Component最终通过Subscribe的方式接收到更新后的State,当然派发 Action 的Component 与 Subscriber 对应状态的 Component 大部分情况下不是一个。
上面是根据上述示例来画的简图,下方我们可以脱离上述demo, 整理了一个图。从下图中不难看出,平时在开发时,Component一般是有多个的,而Store只有一个,这些Component都像Store派发Action修改对应的状态,并且可以通过Subscriber来监听对应状态值的改变。
而Reducer也可以是多个,建议将Reducer按照修改状态的类型或者相关的业务逻辑进行拆分,拆分成多个业务模块。修改不同的状态时,会调用不同的Reducer。
上述我们是声明定义了一个Reducer ,如果修改State的东西都写在一个方法里,难免会有些难于维护。所以一般会对Reducer进行拆分,下方是对上述Reducer拆分后的代码。当然运行效果与之前的是一样的,下方也是推荐用法。
虽然该Demo, 使用Redux实现会比较麻烦,使用组件内部的State完全可以实现,因为是为了窥探Redux的使用方式,所以我们就用Redux实现了该demo。但是如果是跨组件的数据交流,该方式就比较合适了。
本篇博客就先到这儿吧,虽然本篇博客介绍了Redux, 但是在开发中很少直接使用,一般会结合着其他框架及中间件使用。之前还积累了一些 react-redux, 以及redux-thunk、redux-saga 的东西,下篇博客把react-redux相关的东西在总结一下,做个记录也便于自己后期翻阅。最后附上redux的文档链接,有啥问题可翻阅https://www.redux.org.cn/。
ReactNative之Redux详解的更多相关文章
- [转] ReactNative Animated动画详解
http://web.jobbole.com/84962/ 首页 所有文章 JavaScript HTML5 CSS 基础技术 前端职场 工具资源 更多频道▼ - 导航条 - 首页 所有文章 ...
- ReactNative使用 react-navigation 详解
react-navigation是官方主推的导航组件,致力于解决导航卡顿,数据传递,Tabbar和navigator布局,支持redux. 最新版本为3.x,大多文档介绍的是 1.x 或 2.x 的用 ...
- react-native ListView使用详解
刚好今天七夕,呆萌的程序猿没有妹纸,刚好发小明天结婚,我还在异地,晚上还要苦逼的赶火车.趁着下午比较闲,更新一下Blog,也算是在百无聊赖之时给众多单身程序猿们的小福利吧,虽然已经好久没更了...囧 ...
- ReactNative WebView组件详解
在开发Android的时候,一般我们会有一些加载网页的需求,或者执行一些JavaScript,我们都知道在Android中实现这个功能的控件是WebView,在ReactNative中也有实现此类需求 ...
- windows 64位下,React-Native环境搭建详解 (Android)
React-Native环境搭建需要: 1.安装Java JDK 2.安装Android Studio 3.安装node.js 4.安装git 5.安装Python 2.x (注意目前不支持Pytho ...
- redux详解
redux介绍 学习文档:英文文档,中文文档,Github redux是什么 redux是一个独立专门用于做状态管理的JS库(不是react插件库),它可以用在react, angular, vue等 ...
- 从Flux到Redux详解单项数据流
从Flux到Redux是状态管理工具的演变过程,但两者还是有细微的区别的.但是最核心的都还是观察者模式的应用. 一.Flux 1. Flux的处理逻辑 通俗来讲,应用的状态被放到了store中,组件是 ...
- 九、小程序 Redux详解与在小程序中怎么使用(action和reducers)
什么是Redux Redux我们可以把它理解成一个状态管理器,可以把状态(数据)存在Redux中,以便增.删.改.例如: 从服务器上取一个收藏列表,就可以把取回来的列表数据用Redux管理,多个页 ...
- react-native flex 布局 详解
而在React Native中,有4个容器属性,2个项目属性,分别是: 容器属性:flexDirection flexWrap justifyContent alignItems 项目属性( ...
随机推荐
- Flask框架(二)—— 反向解析、配置信息、路由系统、模板、请求响应、闪现、session
Flask框架(二)—— 反向解析.配置信息.路由系统.模板.请求响应.闪现.session 目录 反向解析.配置信息.路由系统.模板.请求响应.闪现.session 一.反向解析 1.什么是反向解析 ...
- CF553C Love Triangles(二分图)
Tyher推的好题. 题意就是给你一些好边一些坏边,其他边随意,让你求符合好坏坏~,或者只包含好好好的三元环的无向图个数. 坏坏的Tyher的题意是这样的. 再翻译得更加透彻一点就是:给你一些0(好边 ...
- Mac 打造开发工作环境
近日公司配的dell笔记本越来越难担重任(主要是CPU太差,本人是Java开发,IDE一编译CPU就100%),于是狠下心入手了一台常规顶配Macbook Pro,现记录新本本的调教过程. Homeb ...
- 《NVM-Express-1_4-2019.06.10-Ratified》学习笔记(8)
8 Feature(特性) 8.1 固件升级过程 固件升级通过重启激活的过程是: 1. 主机发一个Firmware Image Download命令,下载固件映像版本到controller.可能有多个 ...
- 区间K大数
区间K大数 问题描述 给定一个序列,每次询问序列中第l个数到第r个数中第K大的数是哪个. 输入格式 第一行包含一个数n,表示序列长度. 第二行包含n个正整数,表示给定的序列. 第三个包含一个正整数m, ...
- Spring学习之旅(七)--SpringMVC视图
在之前的实例中我们只是在 Controller 中返回了 home 字符类型的值,而没有直接生成可以在浏览器中直接渲染的 HTML,这是因为 SpringMVC 将请求处理的逻辑和视图渲染的实现进行了 ...
- Liunx学习总结(二)--目录和文件管理
之前我们了解了什么是 liunx ,并且认识了它的目录结构,今天我们就来学习下如何进行目录和文件的管理. 创建目录 语法: mkdir [-mp] 目录名称 选项与参数 -m :配置文件的权限喔!直接 ...
- Java生成二维码(Java程序都可以使用)
工具类,链接:https://pan.baidu.com/s/18U399fTH5wBJPnL97pAekg 提取码:bmw7 注:里面的corejar包是使用的zxing的代码,我只是将其导出的ja ...
- 一个手写的Vue放大镜,复制即可使用
一个手写的vue放大镜 组件使用less,请确保已安装loader 本组件为放大镜组件,传参列表为: width: 必传,设置放大镜的宽高(正方形),放大区域等同,放大倍数为2倍 picList:必传 ...
- NLP(一)语料库和WordNet
访问语料库 NLTK数据库的安装:http://www.nltk.org/data.html NLTK语料库列表:http://www.nltk.org/nltk_data/ 内部访问(以Reuter ...