react native基于redux架构实现登陆和购物车

关于React redux概念性的东西可以阅读Redux中文文档和阮一峰老师的redux入门教程,但是实践出真知,所以上手才是最重要的,下面就是基于redux的实现,请看截图:http://blog.****.net/sinat_17775997/article/details/70861065

react native基于redux架构实现登陆和购物车

分两块描述,先说登陆,登陆的时候,我们需要拿到登陆信息,也就是token,然后在获取购物车相关信息的时候带上token去请求数据,

购物车,我们需要实时的改变购物车的数量,使得下方购物车数量显示正确,当然上面的截图只是拿到了数量,但是没显示到下方的导航栏上,自己加上即可,比较简单

先分析需求,登陆时调接口,拿到token值,加载图相应显示与隐藏,登陆成功跳转到首页(其他页面一样),保存token值

在login.js文件中,当用户点击登陆时走对应的方法,我这里拟定是buttonRegisterOrLoginAction方法,下面截图:

[html] view plain copy
  1. import {performLoginAction} from '../../actions/LoginAction'  
  2. //用户登录/注册  
  3. buttonRegisterOrLoginAction(position) {  
  4.     const {navigator, dispatch} = this.props;  
  5.     if (position === 0) {  
  6.         //用户登录  
  7.         if (username === '') {  
  8.             toastShort('用户名不能为空~');  
  9.             return;  
  10.         }  
  11.         if (password === '') {  
  12.             toastShort('密码不能为空~');  
  13.             return;  
  14.         }  
  15.         //调用登陆接口,获取token,并保持状态  
  16.         dispatch(performLoginAction(username, password));  
  17.     } else if (position === 1) {  
  18.         //用户注册  
  19.     }  
  20. }  

判断完不能为空,从props中拿到dispatch,分发到相应的action,并把参数传入,在action里面,我们做网络请求以及逻辑处理,

[javascript] view plain copy
  1. export function performLoginAction(username, password) {  
  2.     return (dispatch) => {  
  3.         dispatch(performLogin());  
  4.         fetch(HOST+LOGIN+'?username='+username + '&password='+password)  
  5.             .then((response) => response.json())//取数据  
  6.             .then((responsetext) => {  
  7.                 if (responsetext.result === 1) {  
  8.                     //登录成功..  
  9.                     toastShort('登陆成功~');  
  10.                     dispatch(receiveLoginResult(responsetext))  
  11.   
  12.                 } else {  
  13.                     dispatch(errorLogin())  
  14.                     toastShort(responsetext.msg);  
  15.                 }  
  16.             }).catch((error) => {  
  17.             toastShort('登陆错误~');  
  18.             //toastLong(error)  
  19.         });  
  20.     }  
  21. }  

这里我是用的get请求,将参数拼接到url里面,当开始登陆,分发相应的action,并根据返回的result判断是否登陆成功,下面是表明3种状态的方法:

[html] view plain copy
  1. //登陆失败  
  2. function errorLogin() {  
  3.     return {  
  4.         type: types.ERROR_LOGIN_ACTION, //自己定义的常量,已区分不同action  
  5.     }  
  6. }  
  7. //开始登陆  
  8. function performLogin() {  
  9.     return {  
  10.         type: types.PERFORM_LOGIN_ACTION,  
  11.     }  
  12. }  
  13. //登陆成功  
  14. function receiveLoginResult(result) {  
  15.     return {  
  16.         type: types.RECEIVE_LOGIN_ACTION,  
  17.         data: result.data  
  18.     }  

根据不同的结果分发不同的type和data给reducer处理

在loginReducer里面是对不同store的处理:

[javascript] view plain copy
  1. const initialState = {  
  2.     isLogin:false,  
  3.     loading : false,  
  4.     data:[],  
  5.     status:null  
  6. }  
  7.   
  8. export default function login(state = initialState, action){  
  9.     switch (action.type) {  
  10.         case types.PERFORM_LOGIN_ACTION:    //开始登陆  
  11.                   return {  
  12.                       ...state,  
  13.                       state:'doing',  
  14.                       loading: true,  
  15.                       isLogin:false  
  16.                   };  
  17.         case types.ERROR_LOGIN_ACTION:      //登陆失败  
  18.             return {  
  19.                 ...state,  
  20.                 state:null,  
  21.                 loading: false,  
  22.                 isLogin:false  
  23.             };  
  24.         case types.RECEIVE_LOGIN_ACTION:    //完成登陆  
  25.                   return  {  
  26.                       ...state,  
  27.                       state:'done',  
  28.                        loading: false,  
  29.                        data: action.data,  
  30.                        isLogin:true  
  31.                   };  
  32.         default:  
  33.             return state;  
  34.     }  
  35. }  
首先初始化各种属性,然后根据action.type来判断不同的事件,给相应的属性赋值,当开始登陆的时候,加载图开始显示,登陆失败或者登陆完成加载图隐藏,登陆成功,获得返回的数据,并且把isLogin变为true,

在 reducer.js里面把loginReducer加到里面

[html] view plain copy
  1. import {combineReducers} from 'redux';  
  2. import login from './LoginReducer';  
  3. import goods from './GoodsReducer';  
  4.   
  5. const rootReducer = combineReducers({  
  6.     login,  
  7.     goods  
  8. })  
  9. export default rootReducer;  
最后在login.js里面,render里,做相应的操作,使加载图正确显示


[html] view plain copy
  1. render() {  
  2.     let {login} = this.props;  
  3.     console.log(login)  
  4.     return (      
  5.     <View >  
  6.     //相应的布局  
  7.     <Loading visible={login.loading}/>  
  8.     </View>  
     这里获取的属性里面的login 要用let,不要用const ,因为我们的加载图需要多次修改状态,

在componentDidUpdate方法里面,我们做相应的跳转操作,单词不要打错,否则很尴尬,这个方法是当组件接受到新的属性和状态改变调用,切绘制完毕,这点很重要,否则我们的加载图会转个不停,具体的组件生命周期在这里,react native组件的生命周期

在compomentDidUpdate里是跳转到主页面,由于chrome一直崩溃,就不发这段代码了,最后在login.js下面还需要这个方法:


[html] view plain copy
  1. function mapStateToProps(state) {  
  2.     const {login} = state;  
  3.     return {  
  4.         login  
  5.   
  6.     }  
  7. }  
  8. export default connect(mapStateToProps)(Login);  
将我们store里面存储的login和Login.js绑定,以便我们方便的获得更改后的数据

至此登陆的逻辑差不多就走通了,购物车的逻辑和登陆的大部分相似,可以自己看代码理解,大部分都有注释,比较好理解,

最后是app的入口,在不同的系统上运行会跑相应系统的,js文件,所以在里面统一处理,统一入口,

如在index.Android.js文件中:

import React, {Component} from 'react';
import {
    AppRegistry,
} from 'react-native';
import root from './App/root';

AppRegistry.registerComponent('Demo', () => root);
统一交由root.js处理,在index.ios.js文件中做相同的操作

在入口组件root.js,把redux导入

[html] view plain copy
  1. mport React, { Component } from 'react';  
  2. import {  
  3. } from 'react-native';  
  4. import {Provider} from 'react-redux'  
  5. import configureStore from './store/configstore'  
  6. const store=configureStore();  
  7. import App from './app'  
  8. import Guide from './guide'  
  9. export default class rootApp extends Component {  
  10.     render() {  
  11.         return (  
  12.             <Provider store={store} >  
  13.             <App/>  
  14.             </Provider>  
  15.         );  
  16.     }  
  17. }  
并配置我们的store,并使用redux-thunk作为middlewares,这里使用了redux-persist将store保存到本地,方便保存登陆信息

[html] view plain copy
  1. import{createStore,applyMiddleware}from 'redux'  
  2. import thunk from 'redux-thunk'  
  3. import {persistStore,autoRehydrate} from 'redux-persist'    //将store保存到本地,保存登陆信息  
  4. import {AsyncStorage} from 'react-native'  
  5. import rootReducer from'../reducers/index'  
  6. const logger=store=>next=>action=>{     //logger  
  7.     if(typeof action==='function') console.log('dispatching a function');  
  8.     else console.log('dispatching',action);  
  9.     let result=next(action)  
  10.     console.log('next state',store.getState)  
  11.     return result;  
  12.   
  13. }  
  14. let middlewares=[logger,thunk]  
  15.   
  16. const creatStoreWithMiddleware=applyMiddleware(...middlewares)(createStore);  
  17.   
  18. // export default function configStore(initiaState) {  
  19. //     const store=creatStoreWithMiddleware(rootReducer,initiaState)  
  20. //     return store;  
  21. // }  
  22. export default function configStore(onComplete:()=>void) {  
  23.     const store=autoRehydrate()(creatStoreWithMiddleware)(rootReducer)  
  24.     let opt={  
  25.         storage:AsyncStorage,  
  26.         transform:[]  
  27.     }  
  28.     persistStore(store,opt,onComplete)  
  29.     return store;  
  30. }  
至此就大功告成了!