redux介绍与入门
一、什么是flux
1.redux的设计思想与flux是差不多一样的,所以我们先来了解什么flux
2.flux是一种设计模式或者说是框架。以mvc模式来划分的话react是mvc中的view, flux相当于mc,m就是model c就是control。那么我们就明白flux到底是什么了,看下图:
flux包含四个部分 Store、Dispatch、Action、View,其中Store就对应着model,Dispatch、Action就组合成了Control。这么划分仅仅是帮助全局理解flux到底是什么。
3.flux就是一种设计模式,当view或者用户产生一个Action时,Dispatch会解析Action根据不同的Action修改Store,被修改的Store会发消息通知View说:我已经修改了过来取我并更新你自己吧。
4.一个简单例子
// store
var Store = {
state:{
loginData:{
type:'login',
data:'no login',
},
logoutData:{
type:'logout',
data:'',
}
},
login:function(data){
this.state.loginData = data;
},
logout:function(data){
this.state.logoutData = data;
},
getState:function(){
return this.state;
},
sendEvent:function(){
this.callback();
},
addChangeListener: function(callback) {
this.callback = callback;
},
removeChangeListener: function(callback) {
}
} // Dispatch
var Dispatcher = require('flux').Dispatcher;
var dispatch = new Dispatcher();
dispatch.register(function(payload){
switch (payload.type){
case 'login' :
Store.login(payload);
Store.sendEvent();
break;
case 'logout':
Store.logout(payload);
Store.sendEvent();
break;
}
}); // View
Store.addChangeListener(()=>{
console.log('{\nloginData:{type:'+Store.getState().loginData.type + ' data:' + Store.getState().loginData.data+ '}');
console.log('logoutData:{type:'+Store.getState().logoutData.type + ' data:' + Store.getState().logoutData.data+ '}\n}');
}); // Action
var loginAction = {
type: 'login',
data: 'login sucessed'
};
var logoutAction = {
type: 'logout',
data: 'logout sucessed'
};
console.log('登录....');
dispatch.dispatch(loginAction);
console.log('退出....');
dispatch.dispatch(logoutAction);
二、redux
1.我们先看看看官网的一个例子
var Redux = require('redux')
var createStore = Redux.createStore function counter(state = 0, action) {
switch (action.type) {
case 'INCREMENT':
return state + 1
case 'DECREMENT':
return state - 1
default:
return state
}
}
// 创建store
let store = createStore(counter)
store.subscribe(() =>
console.log(store.getState())
) store.dispatch({ type: 'INCREMENT' })
//
store.dispatch({ type: 'INCREMENT' })
//
store.dispatch({ type: 'DECREMENT' })
//
可以看到redux与flux原理是一样的,只是实现不一样。
1.redux把dispatch封装到了Store里
// 所以我们可以直接通过store来发送dispatch
store.dispatch({ type: 'INCREMENT' })
2.抽象出一个reducer概念(counter就是一个reducer),reducer就是一个[根据不同的dispatch处理并生产新的state的一个程序]。
// 处理自增、或者自减的程序
function counter(state = 0, action) {
switch (action.type) {
case 'INCREMENT':
return state + 1
case 'DECREMENT':
return state - 1
default:
return state
}
}
要理解redux,其实就是要理解Redux提供的Store与reducer。
三、react中使用redux
我们将会重头创建一个React-native项目,然后加入redux框架
#初始化一个react-native项目
$ react-native init reduxTest
$ cd reduxTest/ios
$ open reduxTest.xcodeproj
#这样就创建并打开了一个iOS的react-native项目
1.添加app.js
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
TouchableHighlight
} from 'react-native';
class App extends Component {
onPress(){ }
render() {
let welcome = this.props.appInfo?this.props.appInfo.welcome:'Welcome to Redux test!'
return (
<View style={styles.container}>
<Text style={styles.welcome}>
{welcome}
</Text>
<TouchableHighlight onPress={this.onPress.bind(this)}>
<Text >
Click me!
</Text>
</TouchableHighlight>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
});
module.exports = App;
2.修改reduxTest/index.ios.js
import React, { Component } from 'react';
import {
AppRegistry,
} from 'react-native';
import App from './app'
export default class reduxTest extends Component {
render() {
return (
<App></App>
);
}
}
AppRegistry.registerComponent('reduxTest', () => reduxTest);
这时候我们得到一个简单的测试app,下面我通过redux来管理app组件的state(redux把state映射到props)。
效果:当点击Click me! 按钮时,会吧welcome信息改为 have clicked!
具体流程就是:
(1).点击 Click me! 按钮 ,会通过redux的Store发送一个dispatch给reducer,reducer把welcome改为‘have clicked’
(2).然后redux会通知app 组件重新渲染
3.安装redux、react-redux、redux-thunk
$ npm install redux --save
$ npm install react-redux --save
$ npm install redux-thunk --save
3.直接上源码,代码后面有解释
总共涉及4个文件,需要重点关注的代码将会被标红。
- index.ios.js -- 创建store
- app.js -- 根据store的改变做出相应的处理、用户点击时发出action
- reducer.js -- 处理action
- action.js -- 具体的action
index.ios.js:
import React, { Component } from 'react';
import {
AppRegistry,
} from 'react-native'; import App from './app'
import appReducer from './reducer' import {createStore,
applyMiddleware} from 'redux';
import {Provider} from 'react-redux';
import thunk from 'redux-thunk'; let store = createStore(appReducer,
applyMiddleware(thunk) // 用于异步的action
); export default class reduxTest extends Component {
render() {
return (
<Provider store={store}>
<App></App>
</Provider> );
}
}
AppRegistry.registerComponent('reduxTest', () => reduxTest);
解析
这里引入了四个redux相关组件
- createStore --- 是一个函数,用于创建store
- applyMiddleware --- 是一个函数,用于使用中间件
- hunk --- 是一个函数,是中间件用于使action函数支持异步;
- Provider --- 是一个react组件,主要提供一个全局的store使得它的子组件都能访问到
创建store的代码:
let store = createStore(
appReducer,
applyMiddleware(thunk) // 用于异步的action
);
/**
@appReducer :是一个reducer,我们说过是用于处理action的。
@applyMiddleware(thunk) : 应用一个叫thunk的中间件,任何一个action执行前会先执行thunk 这里我们应该记住:
store提供一个保存state的地方
store也提供了一个发出dispatch的方法
store也提供了一个监听state的方法
*/
Provider:Provider是提供者,意思就是给他的子组件提供一个store,这个store就是我们上面创建的。
app.js:
import React, { Component } from 'react';
import {
AppRegistry,
StyleSheet,
Text,
View,
TouchableHighlight
} from 'react-native';
import {connect} from 'react-redux';
import {bindActionCreators} from 'redux'; import WelcomeAction from './action' class App extends Component {
// 定义 上线文里store属性的类型为object
static contextTypes = {
store: React.PropTypes.object
}
componentDidMount() {
// store的作用1: 监听state的变化
const { store } = this.context;
store.subscribe(
()=>{
// store的作用2: 获取state
let state = store.getState();
// state改变了
console.log('state:',state);
}
);
}
onPress(){
// 1.直接用store发生dipatch
let action = {
type:'welcome',
data:{
text:'have clicked from app.js',
}
}
// store的作用3: 发送dispatch
this.context.store.dispatch(action) // this.props.onPressAction()
}
render() {
let welcome = this.props.welcome
return (
<View style={styles.container}>
<Text style={styles.welcome}>
{welcome}
</Text>
<TouchableHighlight onPress={this.onPress.bind(this)}>
<Text >
Click me!
</Text>
</TouchableHighlight>
</View>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
justifyContent: 'center',
alignItems: 'center',
backgroundColor: '#F5FCFF',
},
welcome: {
fontSize: 20,
textAlign: 'center',
margin: 10,
},
});
function mapStateToProps(state) {
return {
welcome: state.welcome
}
}
function mapDispatchToProps(dispatch) {
return {
onPressAction:bindActionCreators(WelcomeAction,dispatch),
}
}
module.exports = connect(mapStateToProps,mapDispatchToProps)(App);
解析
(1)获取store
因为app组件是Provider组件的子组件,所以app组件跟Provider组件是共享一个context(上下文)的 --- 这个是react的规定,不了解的请自行补相应知识。
只要在app组件定义一下store的类型就能使用了
// 定义 上线文里store属性的类型为object
static contextTypes = {
store: React.PropTypes.object
}
// 通过下面就能获取到store
this.context.store
这个store是与创建Provider时传入的store是同一个
<Provider store={store}>
<App></App>
</Provider>
(2)使用store
获取到store之后我们就可以用于发送dispatch、监听state了
发送dispatch:
let action = {
type:'welcome',
data:{
text:'have clicked from app.js',
}
}
// store的作用3: 发送dispatch
this.context.store.dispatch(action)
action参数是一个对象,对象结构没有做要求。
action被dispatch之后会被reducer处理,处理完后就会发一个通知说state已经更新了。
通过下面代码来监听通知
// store的作用1: 监听state的变化
const { store } = this.context;
store.subscribe(
()=>{
// store的作用2: 获取state
let state = store.getState();
// state改变了
// 根据state做相应的渲染
console.log('state:',state);
}
);
我看下面的reducer是怎么处理action的
reducer.js:
function Reducer(state = {welcome:'Welcome to Redux test!'}, action) {
switch (action.type) {
case 'welcome':
return {welcome:action.data.text};
default:
return state
}
}
module.exports = Reducer;
解析:
很简单的处理,如果action的type等于‘welcome’的话,就直接返回一个对象{welcome:action.data.text};
监听者收到的就是这个返回的对象。
值得注意,Reducer的参数 state = {welcome:'Welcome to Redux test!'},是state的默认值
---------------------------------------------------------------------
每次都通过this.context.sotre来dispatch、subscribe,大家都觉得很烦,好吧redux已经做了封装:
引入两个组件:
- connect ---- 用于封装App组件
- bindActionCreators --- 绑定action的构造者
具体使用:
function mapStateToProps(state) {
return {
welcome: state.welcome
}
}
function mapDispatchToProps(dispatch) {
return {
onPressAction:bindActionCreators(WelcomeAction,dispatch),
}
} module.exports = connect(mapStateToProps,mapDispatchToProps)(App);
解析:
function mapStateToProps(state)
正如函数名所表示,它的作用就是把state映射到props上。这里的state是指store保存的state,props是指app组件的props。
这个函数需要返回一个对象
return {
welcome: state.welcome
}
然后通过connect组件封装一下
module.exports = connect(mapStateToProps,mapDispatchToProps)(App);
这样子,在app组件内部就能通过this.props.welcome来获取store保存的state对应的welcome的值了,是不是分方便?
既然state能映射到props,那么dispatch action也能映射
import WelcomeAction from './action'
function mapDispatchToProps(dispatch) {
return {
onPressAction:bindActionCreators(WelcomeAction,dispatch),
}
}
module.exports = connect(mapStateToProps,mapDispatchToProps)(App);
上面的代码意思就是吧dispatch映射到props上,dispatch是sotre的dispatch,props是app的props.
我们可以这样直接发出一个action,
this.props.onPressAction()
onPressaction()等同于 WelcomeAction
WelcomeAction是什么请看往下看:
action.js:
function WelcomeAction () {
// 异步
return (dipatch, getState) => {
return new Promise((resolve,reject)=>{
setTimeout(()=>{
let action = {
type:'welcome',
data:{
text:'have clicked??',
}
}
dipatch(action);
resolve();
},2000);
});
}
// 同步
// return {
// type:'welcome',
// data:{
// text:'have clicked',
// }
// }
}
module.exports = WelcomeAction
WelcomeAction函数用到dispatch等于store.dispatch
这样做的目的是把action独立出来方便单独管理。
action函数,如果需要异步执行就返回一个Promise,同步执行可以直接返回一个新的state
值得注意如果action函数需要异步执行,在创建store的时候必须使用中间件trunk
import thunk from 'redux-thunk';
let store = createStore(
appReducer,
applyMiddleware(thunk) // 用于异步的action
);
redux介绍与入门的更多相关文章
- .NET平台开源项目速览(6)FluentValidation验证组件介绍与入门(一)
在文章:这些.NET开源项目你知道吗?让.NET开源来得更加猛烈些吧!(第二辑)中,给大家初步介绍了一下FluentValidation验证组件.那里只是概述了一下,并没有对其使用和强大功能做深入研究 ...
- Redux介绍及基本应用
一.Redux介绍 Redux的设计思想很简单,就两句话: Web应用是一个状态机,神力与状态是一一对应的 所有的状态,保存在一个对象里面 二.Redux基本概念和API Store Store就是 ...
- freemarker语法介绍及其入门教程实例
# freemarker语法介绍及其入门教程实例 # ## FreeMarker标签使用 #####一.FreeMarker模板文件主要有4个部分组成</br>#### 1.文本,直接输 ...
- (转)私有代码存放仓库 BitBucket介绍及入门操作
转自:http://blog.csdn.net/lhb_0531/article/details/8602139 私有代码存放仓库 BitBucket介绍及入门操作 分类: 研发管理2013-02-2 ...
- NET平台开源项目速览(6)FluentValidation验证组件介绍与入门(转载)
原文地址:http://www.cnblogs.com/asxinyu/p/dotnet_Opensource_project_FluentValidation_1.html 阅读目录 1.基本介绍 ...
- 读写Word的组件DocX介绍与入门
本文为转载内容: 文章原地址:http://www.cnblogs.com/asxinyu/archive/2013/02/22/2921861.html 开源Word读写组件DocX介绍与入门 阅读 ...
- [转帖]Druid介绍及入门
Druid介绍及入门 2018-09-19 19:38:36 拿着核武器的程序员 阅读数 22552更多 分类专栏: Druid 版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议 ...
- Redis介绍及入门安装及使用
Redis介绍及入门安装及使用 什么是Redis Redis is an open source (BSD licensed), in-memory data structure store, use ...
- Mysql数据库的简单介绍与入门
Mysql数据库的简单介绍与入门 前言 一.下载与安装 1.下载 官网下载MYSQL5.7.21版本,链接地址https://www.mysql.com/downloads/.下载流程图如下: 找到M ...
随机推荐
- kindEditor完整认识 PHP上调用并上传图片说明/////////////////////////////z
最近又重新捣鼓了下kindeditor,之前写的一篇文章http://hi.baidu.com/yanghbmail/blog/item/c681be015755160b1d9583e7.html ...
- Java里List取并集方法retainAll不能用来判断是否有重复数据!
网上找的源码 public boolean retainAll(Collection<?> c){ boolean modified = false; Iterator&l ...
- Android--自定义加载框
1,在网上看了下好看的加载框,看了一下,挺好看的,再看了下源码,就是纯paint画出来的,再加上属性动画就搞定了 再来看一下我们的源码 LvGhost.java package com.qianmo. ...
- 实测:Windows 8.1 (Windows Blue) 第三方桌面应用无法支持Retina屏,效果与Windows8.0似无差别。
首先我是在VMWARE下装的Windows Blue,是否改用BootCamp直接装就没问题我不知道,理论上应该无差别. 谣言里那个Windows Blue里的缩放功能可以完美支持Retina,但实际 ...
- Java多线程开发系列之一:走进多线程
对编程语言的基础知识:分支.选择.循环.面向对象等基本概念理解后,我们需要对java高级编程有一定的学习,这里不可避免的要接触到多线程开发. 由于多线程开发整体的系统比较大,我会写一个系列的文章总结介 ...
- Final阶段用户调查报告
组名称:nice! 项目名称:约跑 小组成员:李权(组长).刘芳芳.于淼.宫丽君.韩媛媛 产品下载地址:http://pan.baidu.com/s/1mhIjaS4 问卷时间:2016年12月2号1 ...
- C#中使用正则表达式验证电话号码、手机号、身份证号、数字和邮编
验证电话号码的主要代码如下: public bool IsTelephone(string str_telephone) { return System.Text.RegularExpressio ...
- 接口测试第十二课(fidller过滤)(转)
转自: 经常有人问我,如何只抓手机上某个应用的请求包?在使用fiddler抓手机包的过程中,fiddler会话框上瞬间就满屏了,因为它不仅抓到手机上的请求数据包,也抓到了PC端的网络请求包.这时候很难 ...
- nginx+iis、NLB、Web Farm、Web Garden、ARR
nginx+iis实现负载均衡 在win2008R2上使用(NLB)网络负载均衡 NLB网路负载均衡管理器详解 [译文]Web Farm和Web Garden的区别? IIS负载均衡-Applicat ...
- regeneratorRuntime未定义
babel-preset-stage-2 { "presets": ["es2015", "stage-2"], "plugins ...