美文网首页
在ReactNative中应用Redux

在ReactNative中应用Redux

作者: 天色将变 | 来源:发表于2019-11-25 15:45 被阅读0次

    参考文章

    redux是干嘛用的?

    • 状态管理,将页面中state的状态管理起来,统一进行管理
    • 页面与数据处理分离,页面只负责根据不同状态显示不通的内容;数据处理交给action、reducer。可以理解为MVC中的MV。

    redux中的几个概念:

    • action:用于预处理数据,指的是对数据进行加工,然后将数据dispatch给store
    • reducer:分类处理数据,对于action中加工好的数据,依据不通的type组织成不通的结果值state,该结果值会同步到store中,然后页面会在store中获取到该值。
    • dispatch: 触发动作,可以是在页面中触发action,也可以是在action中改变值后更新页面的操作
    • state:组件内部的状态
    • store:我的理解为全局唯一的一个容器,是action、reducer和页面三者状态的的协调器。
    • type:用于区分操作的标识,常量字符串表示

    redux的调用过程:

    • 页面view中触发(比如点击按钮),会发送消息到action内,
    • action将该消息预处理,区分一下type,然后返回给store,
    • store将分好类的消息,分配到reducer中处理state.
    • reducer接收到带有type的消息以后,找到对应的处理办法,生成新的state返回给store
    • store控制页面渲染

    在rn中集成redux:

    npm install --save redux
    npm install --save react-redux
    npm install --save redux-thunk
    
    // 在项目中的导航使用react-navigation, demo中会用到,也配置上
    npm install --save react-navigation
    npm isntall --save react-native-gesture-handler
    npm install --save react-navigation-stack
    

    示例页面

    有点丑!


    image.png

    项目目录结构

    image.png

    redux开发,分两个部分

    • 项目配置(目录中的root和store),项目中只有一份。
    • 页面开发(目录中的actions、constants 、pages和reducers),应用redux的每个页面一份。demo中都是计算页面Counter的,如果有登录页面,那么会相应增加LoginAction、LoginType、LoginReducer和LoginPage。

    先说对于每个页面的redux

    • CounterPage:所有的页面显示元素都在这里写,同时这个页面通过connect与store绑定。
    • CounterAction:数据的预处理过程。
    • CounterType:用于区分页面操作的标识字符串常量,都在这里定义。
    • CounterReducer:对于不同type处理,组织成最终的state数据。
    CounterPage
    'use strict'
    
    import {
        View, Text, TouchableOpacity,StyleSheet
    } from 'react-native';
    import React, { Component } from 'react';
    import { connect } from 'react-redux';
    import * as counterAction from '../actions/CounterAction';
    
    class CounterPage extends Component {
        render() {
            const { num, add, subtract } = this.props;
            return (
                <View style={{alignItems:'center'}}>
                    <Text style={styles.bodyText}>{num}</Text>
                    <TouchableOpacity onPress={() => add(num)}>
                        <Text style={styles.bodyText}>clickme 加1</Text>
                    </TouchableOpacity>
                    <TouchableOpacity onPress={() => subtract(num)}>
                        <Text style={styles.bodyText}>clickme 减1</Text>
                    </TouchableOpacity>
                </View>
            );
        }
    }
    const styles = StyleSheet.create({
        bodyText:{
            fontSize:30,marginTop:20,backgroundColor:'#dddddd'
        }
    })
    export default connect(
        store => ({
            num: store.CounterReducer.num,
        }),
        dispatch => ({
            add: (num) => dispatch(counterAction.add(num)),
            subtract: (num) => dispatch(counterAction.subtract(num)),
        })
    )(CounterPage)
    

    重点关注的点:

    • 顶部,需要把CounterAction给import进来。
    • 底部,需要使用connect,将CounterPage与store建立关系。
    • connect的第一个参数:
     store => ({
            num: store.CounterReducer.num,
        }),
    

    在当前props中添加一个字段num,其值为CounterReducer中定义的state中的num字段的值,这样就建立的联系。如果CounterReducer中的num发生了变化,当前的props中的num也会发生变化。

    • connect的第二个参数:
    dispatch => ({
            add: (num) => dispatch(counterAction.add(num)),
            subtract: (num) => dispatch(counterAction.subtract(num)),
        })
    

    在当前props中添加两个函数add和subtract,其值是调用的CounterAction中的add和subtract。这样页面就可以通过props中的这两个方法来调用action中的方法来,如此即将view和action建立来联系。

    • 看render方法
    const { num, add, subtract } = this.props;
    

    connect中定义的方法和字段,都是从this.props中获取的。

    CounterType
    export const COUNTER_ADD = 'COUNTER_ADD'; // 加1标识
    export const COUNTER_SUBTRACT = 'COUNTER_SUBTRACT'; // 减1标识
    
    CounterAction
    'use strict'
    import * as types from '../constants/CounterType';
    export function add(value){
        const resultValue = value+1;
        return dispatch=>{
            dispatch(result(types.COUNTER_ADD,resultValue));
        }
    }
    export function subtract(value){
        const resultValue = value-1;
        return dispatch=>{
            dispatch(result(types.COUNTER_SUBTRACT,resultValue));
        }
    }
    function result(type,value){
        return {
            type:type,
            num:value
        }
    }
    

    需要关注的点:

    • import了CounterType,在result方法内将type传入,这样reducer中就可以拿到这个type了。
    • 定义了方法add和subtract,在方法内对数据进行了处理,“const resultValue = value-1;”,处理完后,使用dispatch进行触发,将result方法的返回值给了store。记得一定要用dispatch。
    CounterReducer
    'use strict'
    import * as types from '../constants/CounterType';
    const initState = {
        num: 0
    }
    export default function CounterReducer(state = initState, action) {
        switch (action.type) {
            case types.COUNTER_ADD:
                return {
                    ...state,
                    num: action.num
                }
            case types.COUNTER_SUBTRACT:
                return {
                    ...state,
                    num: action.num
                }
            default:
                return initState;
        }
    }
    

    需要关注的点:

    • initState,一般会定义一个默认值,在“export default function CounterReducer(state = initState, action)”中。
    • 参数action内有,CounterAction中传递的参数type和num。
    • switch区分不同的type,组织不同的state状态值。
    • 在reducers目录中还有个index.js。项目中有多个页面,那么就会有多个XXXReducer,这里的index.js目的是将所有的Reducer都集中起来。
    'use strict'
    
    import {
        combineReducers
    } from 'redux';
    
    import CounterReducer from './CounterReducer';
    
    export default combineReducers({
        CounterReducer:CounterReducer,
    })
    

    项目中Redux的配置

    ConfigueStore.js
    'use strict'
    
    import {createStore,applyMiddleware} from 'redux';
    import thunkMiddleware from 'redux-thunk';
    import rootReducer from '../reducers/index'
    
    const createStoreWithMiddleware = applyMiddleware(thunkMiddleware)(createStore);
    
    export default function configueStore(initState){
        return createStoreWithMiddleware(rootReducer,initState);
    }
    
    • 创建了store,并与所有reducer建立关联
    App.js

    这是导航管理中,将所有的页面都集中起来建立关系

    'use strict'
    import React from 'react';
    import CounterPage from '../pages/CounterPage';
    import { createAppContainer } from 'react-navigation';
    import { createStackNavigator } from 'react-navigation-stack';
    
    const App = createStackNavigator({
        CounterPage: { screen: CounterPage }
        // 这里可以增加其他Page
    });
    export default createAppContainer(App);
    
    Root.js
    'use strict'
    import React,{Component} from 'react';
    import {Provider} from 'react-redux';
    import App from './App'
    import ConfigueStore from '../store/ConfigueStore';
    const store = ConfigueStore();
    export default class Root extends Component{
        render(){
            return (
                <Provider store={store}>
                    <App />
                </Provider>
            );
        }
    }
    
    • 创建store,‘const store = ConfigueStore();’
    • 引入App,里面是导航管理中的所有页面
    • 使用Provider,将store当作属性传入,并包裹App,这样就可以将store与App中的所有页面建立关系。这是redux生效的入口
    • 应用入口的index.js,入口要指向Root
    import {AppRegistry} from 'react-native';
    import Root from './src/root/Root';
    import {name as appName} from './app.json';
    
    AppRegistry.registerComponent(appName, () => Root);
    

    这样就捋顺了:
    应用入口index - Root -(store,reducer,pages三者建立关系)-具体页面内容应用redux

    demo

    https://github.com/zrfzhouruifeng163/RNReduxExample

    相关文章

      网友评论

          本文标题:在ReactNative中应用Redux

          本文链接:https://www.haomeiwen.com/subject/xstjwctx.html