转载请注明出处:王亟亟的大牛之路
这两天组里来了几个新人,有的用过redux,有的没用过,为了让他们上手或者理解的更透彻,就写了个demo,代码逻辑来源于https://github.com/ninty90/react-native-redux-demo
开篇前先安利
android:https://github.com/ddwhan0123/Useful-Open-Source-Android
react-native:https://github.com/ddwhan0123/Useful-Open-Source-React-Native
源码地址:https://github.com/ddwhan0123/ReduxDemo
演示效果:
理论知识:
http://www.ruanyifeng.com/blog/2016/09/redux_tutorial_part_one_basic_usages.html
http://www.jianshu.com/p/0e42799be566
http://www.jianshu.com/p/3334467e4b32
理论知识重复炒冷饭等于制造网络垃圾,所以贴上几篇我觉得写得不错的给大家瞅瞅
核心理念:
Store:应用只有一个单一的 Store,State是这个状态集合某一时刻的状态
Action:改变state的载体,也是Store的数据源
Reducer:更新Store的具体操作者
ok,你现在肯定云里雾里的,我们用代码边写边解释
项目结构:
Action相关
MathType
export const ADD_TYPE = 'ADD_TYPE';
export const MINUS_TYPE = 'MINUS_TYPE';
这里是2个常量,"加类型","减类型",我们每种action都有他相对应的类型,可以写在Action里也可以写一个类型对他进行划分,我习惯是拆的越细越好
MathAction
// action类型
import * as types from '../type/MathType';
// 每一个action方法返回一个新的"state"对象,他就是应用当前的状态
export function add(intvalue) {
console.log('---> MainAction add intvalue ' + intvalue);
return {
type: types.ADD_TYPE,
result: intvalue,
}
};
export function minus(intvalue) {
console.log('---> MainAction minus intvalue ' + intvalue);
return {
type: types.MINUS_TYPE,
result: intvalue,
}
};
Reducer相关
MathReducer
import * as Type from'../type/MathType';
//初始化
const initState = {
result: 0
};
export default function mathReducer(state = initState, action = {}) {
switch (action.type) {
case Type.ADD_TYPE:
console.log('---> mathReducer action.type ' + action.type);
return {
...state,
result: action.result + 10,
};
break;
case Type.MINUS_TYPE:
console.log('---> mathReducer action.type ' + action.type);
return {
...state,
result: action.result - 10,
};
default:
return state;
}
}
肉眼看起来很简单,这里接受两种类型的action一个是➕,一个是➖,每次他都会改变传入参数的值,而且是一定改变,一定会+10或者-10!
reducer只是一个方法,传入什么,返回什么。结果是个恒定值,只要传入参数不变,返回参数一定也不变!
reducers
import Mathreducer from './Mathreducer';
import {combineReducers} from 'redux';
export default combineReducers({
mathStore: Mathreducer,
});
这是一个reducer的大容器,你所有reducer丢一个方法里也不是不能处理,但是性能差加难以维护,所以redux提供combineReducers来帮你整合reducer
Store相关
store是个应用级持有的对象,所以我们把他放到了"根"页面里去做初始化,因为我们之后还会用到异步action,所以还用到redux-thunk
的相关内容
import {Provider} from 'react-redux';
import {createStore, applyMiddleware} from 'redux';
import thunk from 'redux-thunk';
import reducers from'./reducer/reducers';
const middlewares = [thunk];
const createSoreWithMiddleware = applyMiddleware(...middlewares)(createStore);
import React from 'react';
import Main from'./Main';
export default class App extends React.PureComponent {
constructor(props) {
super(props);
this.state = {
store: createSoreWithMiddleware(reducers)
}
}
//前面一些只是对象,方法相关的操作,肉眼可以识别,Provider是让我们决定使用redux的一个原因,它可以让我们操作容器内的组件却不需要手动传递内容
//想想复杂应用来一个 4层以上的json要你你自己操作的话的工作量吧
render() {
return (
<Provider store={this.state.store}>
<Main/>
</Provider>
)
}
}
只需要在外面套一层,所有子控件的属性竟在掌握!
页面代码
import React from'react';
import {connect} from 'react-redux';
//加减的两种action
import {add, minus} from './action/MathAction';
import {
Text,
View,
TouchableHighlight,
} from 'react-native';
class Main extends React.Component {
constructor(props) {
super(props);
this.addPress = this.addPress.bind(this);
this.minusPress = this.minusPress.bind(this);
//初始值,也可以是外部传入
this.state = {
intvalue: 100,
}
}
addPress() {
console.log('---> Main addPress');
this.props.dispatch(add(this.state.intvalue));
}
minusPress() {
console.log('---> Main minuPress');
//dispatch(action) 方法更新 state
this.props.dispatch(minus(this.state.intvalue));
}
//状态变化时会被调用
shouldComponentUpdate(nextProps, nextState) {
console.log('---> Main shouldComponentUpdate');
if (nextProps.result !== this.props.result) {
this.state.intvalue = nextProps.result;
console.log('---> Main shouldComponentUpdate this.state.intvalue ' + this.state.intvalue);
return true;
}
}
render() {
console.log('---> Main render');
return (
<View style={{justifyContent: 'center'}}>
<TouchableHighlight onPress={this.addPress}>
<Text style={{fontSize: 15}}>
按我会加
</Text>
</TouchableHighlight>
<TouchableHighlight style={{marginTop: 30}} onPress={this.minusPress}>
<Text style={{fontSize: 15}}>
按我会减
</Text>
</TouchableHighlight>
<Text style={{marginTop: 30, color: '#ffaa11'}}>{this.state.intvalue}</Text>
</View>
)
}
}
function select(store) {
return {
result: store.mathStore.result,
}
}
//connect方法建立数据与状态的关系,达到刷新ui的效果
export default connect(select)(Main);
这样这个简单的demo就讲完了,什么?看不懂,我也觉得 这说的是啥啊,过程都没讲清楚,ok 看下console你就明白了!
//首页被加载出来
05-19 20:52:49.094 5992-24741/? I/ReactNativeJS: ---> Main render
//页面点击了 “按我会加”
05-19 20:52:57.746 5992-24741/? I/ReactNativeJS: ---> Main addPress
//action得到了响应获取到了 100(正常的方法调用嘛?继续看!)
05-19 20:52:57.747 5992-24741/? I/ReactNativeJS: ---> MainAction add intvalue 100
//传递到了reducer获取到了触发的类型
05-19 20:52:57.747 5992-24741/? I/ReactNativeJS: ---> mathReducer action.type ADD_TYPE
//页面收到了state改变的讯息,回调被触发
05-19 20:52:57.759 5992-24741/? I/ReactNativeJS: ---> Main shouldComponentUpdate
//新的值是之前的100+reducer的10=110
05-19 20:52:57.759 5992-24741/? I/ReactNativeJS: ---> Main shouldComponentUpdate this.state.intvalue 110
//刷新数据
05-19 20:52:57.759 5992-24741/? I/ReactNativeJS: ---> Main render
//第二次操作,不解释了
05-19 20:53:02.010 5992-24741/? I/ReactNativeJS: ---> Main minuPress
05-19 20:53:02.010 5992-24741/? I/ReactNativeJS: ---> MainAction minus intvalue 110
05-19 20:53:02.010 5992-24741/? I/ReactNativeJS: ---> mathReducer action.type MINUS_TYPE
05-19 20:53:02.015 5992-24741/? I/ReactNativeJS: ---> Main shouldComponentUpdate
05-19 20:53:02.015 5992-24741/? I/ReactNativeJS: ---> Main shouldComponentUpdate this.state.intvalue 100
05-19 20:53:02.015 5992-24741/? I/ReactNativeJS: ---> Main render
action reducer本身看起来平淡无奇,但是在store内轮转使得我们省去了大量setState的人工操作,避免了各种不可描述的render().
但是 redux处理不好会各种多次render页面,之后的文章我会讲一讲异步的action和react-native优化
我是王亟亟!我们下篇见