ReactNative 之搭配框架 Redux

Posted on By Vivian Sun

Redux简介

Redux是继FB Flux 架构后推出的管理 React 数据流的亮眼之作。

可以说Redux是对Flux 架构的一些简化。 Redux 限定一个store,让应用中数据结果集中化,提高可控性。

Action、Reducer、及 Store

Redux 主要分为三个部分 Action、Reducer、及 Store. 下面以counter Sample核心Code为例.

Action

action 主要用来传递操作 State 的信息。 Action是一个plain object(空对象或者key/value键值对),

action内必须使用一个字符串类型的type字段。 当应用规模越来越大时,建议使用单独的模块或者文件来存放action。

核心Code

使用函数来产生action

export const ADD_ITEM = 'ADD_ITEM';
export const MINUS_ITEM = 'MINUS_ITEM';


export function addItem() {
    console.log('action--' + 'addItem');
    return {
        type: ADD_ITEM,
    }
}

export function minusItem() {
    return {
        type: MINUS_ITEM,
    }
}

Reducer

可以认为Reducer是处理Action的逻辑操作。 Reducer一般为简单的处理函数,通过传入旧的state和action来更新state。

(previousState, action) => newState

核心Code

import {ADD_ITEM, MINUS_ITEM} from '../action/action';

export function counter(state = 0, action) {
    console.log('reduce fuction...');
    switch (action.type) {
        case ADD_ITEM:
            return state + 1;
        case MINUS_ITEM:
            return state - 1;
        default:
            return state;
    }
}

export function counter1(state = 0, action) {
    console.log('reduce fuction1...');


    switch (action.type) {
        case ADD_ITEM:
            return state + 4;
        default:
            return state;
    }

}

注意:不要在reducer里做如下操作: • 修改传入参数 • 执行有副作用的操作,如API请求和路由跳转 • 调用非纯函数,如Date.now()或Math.random()

Redux可以分多个Reducer分别处理不同module的逻辑,最后combineReducers,导出一个rootReducer

核心Code

import { combineReducers } from 'redux';
import {counter, counter1} from './counter';

const rootReducer = combineReducers({
    counter1,
    num: counter
});

export default rootReducer;

Store

Action 代表操作消息,Reducer 用来处理消息并更新State。

在 Redux 项目中,Store 是单一的。维护着一个全局的 State. 有如下功能:

  • 维持应用state
  • 提供getState()方法获取state
  • 提供dispatch(action)方法更新state
  • 通过subscribe(listener)注册监听器
  • 通过subscribe(listener)返回的函数注销监听器

Store 是一个把 Action 和 Reducer 结合起来的对象。

核心Code

import { createStore, applyMiddleware} from 'redux';
import thunk from 'redux-thunk';
import logger from 'redux-logger';

import reducer from '../reducers/index';

const createStoreWithMiddleware = applyMiddleware(
    thunk
)(createStore);

export default function configureStore(initialState) {
    console.log('store---' + 'configureStore');
    const store = createStoreWithMiddleware(reducer, initialState);

    return store;
}

Page中使用

class BaseApp extends Component {
    render() {
        const {counter, addItem, minusItem} = this.props;

        return (
            <View style={styles.container}>
                <Text style={styles.welcome}>
                    Clicked: {counter} times
                </Text>
                <TouchableHighlight style={styles.btn} onPress={addItem}>
                    <Text style=>Add</Text>
                </TouchableHighlight>
                <TouchableHighlight style={styles.btn} onPress={minusItem}>
                    <Text style=>Minus</Text>
                </TouchableHighlight>

            </View>
        );
    }

}

function mapStateToProps(state) {
    console.log('mapStateToProps...');
    console.log('state:' + state.counter);
    return {
        counter: state.num,
    }
}

function mapDispatchToProps(dispatch) {
    console.log('mapDispatchToProps...');
    console.log(CounterActions);
    return bindActionCreators(CounterActions, dispatch);
}

export default connect(mapStateToProps, mapDispatchToProps)(BaseApp);

备注是redux源码中部分核心Code,用于理解bindActionCreators方法

// function bindActionCreator(actionCreator, dispatch) {
//     return function () {
//         console.log('***********');
//         for(var i=0;i<arguments.length;i++){
//             console.log(arguments[i]);
//         }
//         return dispatch(actionCreator.apply(undefined, arguments));
//     };
// }

// function bindActionCreators(actionCreators, dispatch) {
//     if (typeof actionCreators === 'function') {
//         return bindActionCreator(actionCreators, dispatch);
//     }

//     if (typeof actionCreators !== 'object' || actionCreators === null) {
//         throw new Error('bindActionCreators expected an object or a function, instead received ' + (actionCreators === null ? 'null' : typeof actionCreators) + '. ' + 'Did you write "import ActionCreators from" instead of "import * as ActionCreators from"?');
//     }

//     var keys = Object.keys(actionCreators);
//     var boundActionCreators = {};
//     for (var i = 0; i < keys.length; i++) {
//         var key = keys[i];
//         console.log('xxxxx---' + keys.length);
//         console.log(key);
//         var actionCreator = actionCreators[key];
//         console.log(actionCreator);
//         if (typeof actionCreator === 'function') {
//             console.log('actionCreator is function...');
//             boundActionCreators[key] = bindActionCreator(actionCreator, dispatch);
//         }
//     }
//     console.log('******************');
//     console.log(boundActionCreators);
//     return boundActionCreators;
// }

Demo Code下载

Redux相关lib

"react-redux": "^4.4.5", // connect function
"redux": "^3.5.2",
"redux-immutable": "^3.0.6", // 不可变state
"redux-logger": "^2.6.1", // 查看log
"redux-thunk": "^2.1.0" // action 里面返回json object的函数

在实际使用中感觉到:Redux对提示开发效率作用不大。但是你会惊喜的发现对问题的排查和维护是多么的方便和效率。

而且从redux-devtools 中打印出来的信息,还能很清晰的get到整个业务逻辑的运作。

Redux

Redux CN

React 数据流管理架构之 Redux 介绍

Redux核心概念

React+Redux系列教程

看漫画学 Redux