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 ...
随机推荐
- 一张图轻松搞懂javascript event对象的clientX,offsetX,screenX,pageX区别
总是会被javascript的event对象的clientX,offsetX,screenX,pageX 弄得头晕,于是决定做个图来区分一下(画得我手那个酸呀....) 先总结下区别: event.c ...
- Coursera台大机器学习课程笔记5 -- Theory of Generalization
本章思路: 根据之前的总结,如果M很大,那么无论假设泛化能力差的概率多小,都无法忽略,所以问题转化为证明M不大,然后上章将其转化为证明成长函数:mh(N)为多项式级别.直接证明似乎很困难,本章继续利用 ...
- python直接执行另一个文件中的代码
看你弄的这么辛苦,给你的方法exec(open(".py","r").read)open(".py",'r').read() 就是读取文件的 ...
- Apache Commons CLI官方文档翻译 —— 快速构建命令行启动模式
昨天通过几个小程序以及Hangout源码学习了CLI的基本使用,今天就来尝试翻译一下CLI的官方使用手册. 下面将会通过几个部分简单的介绍CLI在应用中的使用场景. 昨天已经联系过几个基本的命令行参数 ...
- clock()、time()、clock_gettime()和gettimeofday()函数的用法和区别【转】
转自:http://www.cnblogs.com/krythur/archive/2013/02/25/2932647.html 转自http://blog.sina.com.cn/s/blog_7 ...
- windows系统nginx配置root绝对路径的问题
看了下logs下面的error.log文件,发现路径有问题,修改了conf配置,把root的路径反斜杠要用两个反斜杠进行转义,再次运行正常了.
- angularJS中directive与directive 之间的通信
上一篇讲了directive与controller之间的通信:但是我们directive与directive之间的通信呢? 当我们两个directive嵌套使用的时候怎么保证子directive不会被 ...
- set、def、lambda、内置函数、文件操作
set : 无序,不重复,可以嵌套 .add (添加元素) .update(接收可迭代对象)---等于批量 添加 .diffrents()两个集合不同差 .sysmmetric difference( ...
- JS的兼容函数
获取类名的兼容函数 //obj.getElementsByClassName 只能在现代浏览器中使用,不能在IE8以下使用 //两个参数 classname 类名 obj 范围 function ge ...
- java中filter的用法 内部资料 请勿转载 谢谢合作
filter过滤器主要使用于前台向后台传递数据是的过滤操作.程度很简单就不说明了,直接给几个已经写好的代码: 一.使浏览器不缓存页面的过滤器 Java代码 import javax.servlet ...