1.redux的设计思想与flux是差很少同样的,因此咱们先来了解什么fluxreact
2.flux是一种设计模式或者说是框架。以mvc模式来划分的话react是mvc中的view, flux至关于mc,m就是model c就是control。那么咱们就明白flux究竟是什么了,看下图: ios
flux包含四个部分 Store、Dispatch、Action、View,其中Store就对应着model,Dispatch、Action就组合成了Control。这么划分仅仅是帮助全局理解flux究竟是什么。web
3.flux就是一种设计模式,当view或者用户产生一个Action时,Dispatch会解析Action根据不一样的Action修改Store,被修改的Store会发消息通知View说:我已经修改了过来取我并更新你本身吧。npm
4.一个简单例子redux
// 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);
1.咱们先看看看官网的一个例子react-native
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' }) // 1 store.dispatch({ type: 'INCREMENT' }) // 2 store.dispatch({ type: 'DECREMENT' }) // 1
能够看到redux与flux原理是同样的,只是实现不同。设计模式
1.redux把dispatch封装到了Store里xcode
// 因此咱们能够直接经过store来发送dispatch store.dispatch({ type: 'INCREMENT' })
2.抽象出一个reducer概念(counter就是一个reducer),reducer就是一个[根据不一样的dispatch处理并生产新的state的一个程序]。mvc
// 处理自增、或者自减的程序 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。 app
咱们将会重头建立一个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:
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相关组件
建立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已经作了封装:
引入两个组件:
具体使用:
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 );