美文网首页
在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