ReactNative使用Redux例子

中文文档地址:https://www.redux.org.cn/

导包:

npm install redux-thunk//这个是用来支持发送异步的action,常见如网络请求:请求前触发请求中的action,等请求拿到回调再去触发请求成功和失败的action
npm install --save react-redux
npm install --save redux

一:三个主要概念:Action、Reducer和store

store:所有的state全部在这里面,只可读,无法修改;

Reducer:页面触发不同的action来返回不同的state,他是实际操作state的;

Action:用来触发Reducer返回的,类似后台的接口

Redux的关键方法:

dispatch(ShopAction.add_goods(goods))

这个方法就是将action发送到store里面的reducer里面,store是必须唯一的,但是reducer可以是多个:

//这个表示把多个reducer连接起来,
const rootReducer = combineReducers({
    LoginReducer: LoginReducer,
    ShopReducer:ShopReducer,
});

二.react-redux

只使用Redux是不会自动帮你刷新页面的,他只是一个类似于数据服务的东西,就像后台接口,你给他什么他给你返回对应的,但是你页面展示的变更,则需要你自己来实现,所以需要state与Redux建立关系则需要React-redux。

React-Redux的关键:connect

import {connect} from 'react-redux'; // 引入connect函数

这个connect是用来将你reducer里面的的state关联你当前页面的props中的属性,从而实现动态刷新。

export default connect(
    (state) => ({
        status: state.LoginReducer.status,
        responsedUserMessage: state.LoginReducer.responsedUserMessage,
        hadAddedGoods:state.ShopReducer.hadAddedGoods,
    }),
    (dispatch) => ({
        login: () => dispatch(LoginAction.login()),
        addGoods:(goods)=>{dispatch(ShopAction.add_goods(goods))}
    })
)(GoodsPage)

上面的例子中,(state)表示我当前页面的props中的status即是store中的status,下面的(dispatch)表示将这个方法放到props里面,为什么不能在页面需要的地方调用dispatch({type:'type'}):(注:这里就是发送action到reducer,而action实际上是个对象。)呢,因为你在页面里面是拿不到这个dispatch对象的。最后的Frament1表示这个connect和Fragment1进行管理,如果你第二个页面也用这个reducer,那第二个页面的connect继续使用这个reducer即可

使用时调用this.props.methodName()即可。

三:适用场景:

某个页面的state会在多个页面进行关联使用,如对A页面state的增删改会影响页面B的显示

四:例子

最简单的应用场景:

以Android为例,ViewPage里面有3个Fragment,可以联想天猫。

Fragment1是用户可见的第一个页面,这个页面包含用户信息和加入购物车;

Fragment2是购物车页面,用户在Fragment1添加到购物车的需要在这里进行显示;

Fragment3是用户信息页面,如果用户在Fragment3登录了则Fragment1需要显示用户信息,否则就提示登录,而且该页面附带退出功能,退出后Fragment1的登录状态也需要改变。

分析:如果是原生开发,那么当页面重新显示的时候回调用某个方法,在这个方法对本地存储的数据进行读取展示即可。但是RN中页面重新进入并不会触发任何方法,所以这个行不通。

第一种:RN所有显示均依赖于你自己设置的state,能做的就是当Fragment1触发了加入购物车就实时更新Fragment3中的state,这里可以使用广播也可以使用导航器来传值,但是系统开销大而且不便于维护。

第二种:在global中存储你的数据,把global的数据作为显示源,也是可以的

 

使用Redux:

注:这个例子是参考以下例子:

https://github.com/NextChampion/react-native-redux-navigation-example

这个例子的源代码在

https://github.com/15539158137/Redux_Demo

实际执行效果:

 

这里分为了二部分部分:用户是否登录以及用户信息和购物车信息

为了方便区分,我使用了两个action文件和2个reducer文件,分别对应用户和购物车。下面代码只展示用户对应的这部分

LoginTypes.js:定义登录所需的action的type信息

//这里是为了方便后期维护吧所有的type单独拉出来,直接用字符串传也无所谓
//其实error和out触发的reducer是相同的,但是为了理解,分开
export const LOGIN_IN = 'LOGIN_IN';
export const LOGIN_IN_ERROR = 'LOGIN_IN_ERROR';
export const LOGIN_OUT = 'LOGIN_OUT';

LoginAction.js:action是一个对象,必须包含‘type’字段,可以按需求添加其他字段

import * as LoginTypes from '../types/LoginTypes';

//登录失败
export function loginFail() {
    return {
        type: LoginTypes.LOGIN_IN_ERROR,

    }
}
//登录成功
export function login_in(responseData) {

    return {
        type: LoginTypes.LOGIN_IN,
        responsedUserMessage: responseData,
    }
}

//注销登录
export function login_out() {
    return {
        type: LoginTypes.LOGIN_OUT
    }
}


//如果登录过程中需要显示加载框、提示框,最好把这个操作放在所在页面,因为上传中等等是所在页面独有的state,否则处理弹出框等等很麻烦
export function login() {
    console.log('登录方法');
    return dispatch => {
        // 模拟用户登录
        let result = fetch('https://www.baidu.com/')
            .then((res) => {
                //如果登录接口返回成功,那么把返回的json返回回去
                dispatch(login_in({
                    name: '小明',
                    age: 12,
                    image: '..',
                }));
            }).catch((e) => {
                //如果失败,把错误返回回去。

                dispatch(loginFail());
            })
    }
}

LoginReducer.js:是个方法,在方法里面对不同的action返回不同的数据


import * as LoginTypes from "../types/LoginTypes";

//这里只存储需要全局处理的数据,页面独有的state如input内容的state就在本身的页面使用。
const initialState = {
    status: '离线',//表示当前的登录状态,在线离线两种状态==用0和1当然更好了
    responsedUserMessage: null,//登录后的用户信息

}
export default function LoginReducer(state=initialState, action) {
    switch (action.type) {
        case LoginTypes.LOGIN_IN:
            return {
                ...state,
                status: '在线',
                responsedUserMessage: action.responsedUserMessage,
            }
            break;
        case LoginTypes.LOGIN_IN_ERROR:
            return {
                ...state,
                status: '离线',
                responsedUserMessage: null,
            }
            break;
            case LoginTypes.LOGIN_OUT:
        return {
            ...state,
            status: '离线',
            responsedUserMessage: null,
        }
        break;
        default:
            console.log(state);
            return state;
    }
}

Fragment1.js

'use strict';
import {Provider} from 'react-redux';
import React, {Component} from 'react';
import {connect} from 'react-redux'; // 引入connect函数
import *as LoginAction from '../actions/LoginAction'; // 引入connect函数
import *as ShopAction from '../actions/ShopAction'; // 引入connect函数
import {Platform, Alert,StyleSheet, Text, View, TouchableOpacity} from 'react-native';
const Dimensions = require('Dimensions'); //必须要写这一行,否则报错,无法找到这个变量
const ScreenWidth = Dimensions.get('window').width;
const ScreenHeight = Dimensions.get('window').height;
  class GoodsPage extends React.Component {
    render() {
        const {login}=this.props;//这是js解构赋值的写法等同于this.props.login
        let bean1=  {'type':"LOGIN_IN_DOING"};
        let bean=      {type:"LOGIN_IN_DOING"};
        return (
            
                {this.props.status=="在线"?"欢迎你:"+this.props.responsedUserMessage.name:'请登录'}
                {

                    let goods={name:'商品1:购买毫秒数'+new Date().getTime(),type:0};

                      this.props.addGoods(goods);
                }}>
                    添加商品1到购物车
                

                {

                    let goods={name:'商品2:购买毫秒数'+new Date().getTime(),type:1};

                    this.props.addGoods(goods);
                }}>
                    添加商品2到购物车
                
            
        );
    }
     shouldComponentUpdate(nextProps, nextState) {
        console.log("新的信息store里面的fragment2reducer"+JSON.stringify(nextProps.data));
         // 登录完成,切成功登录
         if (nextProps.status === '登陆成功' && nextProps.isSuccess) {
             return true;
         }
         return true;
     }
};
export default connect(
    (state) => ({
        status: state.LoginReducer.status,
        responsedUserMessage: state.LoginReducer.responsedUserMessage,
        hadAddedGoods:state.ShopReducer.hadAddedGoods,
    }),
    (dispatch) => ({
        login: () => dispatch(LoginAction.login()),
        addGoods:(goods)=>{dispatch(ShopAction.add_goods(goods))}
    })
)(GoodsPage)

注意:关键点在于connect方法,我这个页面同时使用了LoginReducer和ShopReducer

RootReducer.js:将两个reducer合并

import { combineReducers } from 'redux';
import LoginReducer from './LoginReducer';
import ShopReducer from './ShopReducer';

//这个表示把多个reducer连接起来,
const rootReducer = combineReducers({
    LoginReducer: LoginReducer,
    ShopReducer:ShopReducer,
});

export default rootReducer;

 

store.js:这里是创建store的方法


import { createStore, applyMiddleware } from 'redux';
import thunkMiddleware from 'redux-thunk';
import rootReducer from "../../my_redux_test/reducers/RootReducer";
//这里是因为使用了redux-truk的缘故,如果不用,就使用store.createStore即可
const createStoreWithMiddleware = applyMiddleware(thunkMiddleware)(createStore);

export default function configureStore(initialState) {
    const store = createStoreWithMiddleware(rootReducer, initialState)
    return store;
}

 

你可能感兴趣的:(ReactNative)