react-native项目中从零开始使用redux

96
nextChallenger
2.2 2017.07.14 17:42* 字数 1740

本文主要是以我的另一篇文章的思维过程来操作,希望大家使用后可以记住整个过程,从而活学活用,使用到自己的项目中.

参考文章:react-native中使用redux的原理分析及demo

demo地址:github.com/NextChampion/react-native-redux-navigation-example

react native 已更新到0.57.8版本

效果图


效果图

demo简单介绍:

功能:登录页中点击登录,跳转到主页,主页内含有一个大家都很熟悉的counter组件.可以实现简单的加减数操作;

demo逻辑:

登录:

点击登录时,组件的点击方法会发送消息到action内,

action将该消息预处理,即区分一下type,然后返回给store,

store将分好类的消息,分配到reducer中处理state.

reducer接收到带有type的消息以后,找到对应的处理办法,生成新的state返回给store,

store控制页面渲染,跳转到主页;

加减:

点击加号,组件将该点击方法发送到action内,

action预处理该消息,区分是加/减,指定type后,返回消息给store;

store收到预处理后的消息后,将该消息发送给reducer;

reducer收到store发过来的消息,根据消息内的type处理数据,真正进行加/减过程,并且将新的state返回给store;

store收到reduder发过来的新state,控制页面渲染,即页面中数字的变化;

demo特点:

1.区分登录和加减逻辑,并且将不同的state对应不同的组建部分

登录相关的state只有loginPage可用,加减相关的state只有主页面可用;

2.页面切换使用react-navigation控制;

3.该demo大家可以拿去改改部分代码,直接类比内部redux的逻辑实现过程,开发自己的项目;

下面开始详细讲解整个demo的实现过程

1.新建项目


react-native init CountersDemo

2.安装redux相关文件


npm install --save redux

npm install --save react-redux

npm install --save react-navigation

npm install --save redux-thunk

3.建立项目内部文件夹


4.redux相关代码实现过程

1)新建src文件夹存放所有js文件.

2)新建constants,actions,reducers,store,container,pages文件夹

3)(设定类型type) constans文件夹内新建文件loginType,用来划分登录过程中的事件类别


export const LOGIN_IN_DOING = 'LOGIN_IN_DOING'; //正在登陆

export const LOGIN_IN_DONE = 'LOGIN_IN_DONE'; // 登陆完成

export const LOGIN_IN_ERROR = 'LOGIN_IN_ERROR'; // 登陆出错

4.(设定预处理消息过程)actions文件夹内,新建loginAction文件,用来给预处理消息区分各个事件的类别


'use strict';

import * as types from '../constants/loginTypes';// 导入事件类型,用来做分配给各个事件

// 模拟用户信息

let user = {

name: 'zhangsan',

age: 24,

}

// 访问登录接口 根据返回结果来划分action属于哪个type,然后返回对象,给reducer处理

export function login() {

console.log('登录方法');

return dispatch => {

dispatch(isLogining()); // 正在执行登录请求

// 模拟用户登录

let result = fetch('https://www.baidu.com/')

.then((res)=>{

dispatch(loginSuccess(true,user)); // 登录请求完成

}).catch((e)=>{

dispatch(loginError(false)); // 登录请求出错

})

}

}

function isLogining() {

return {

type: types.LOGIN_IN_DOING

}

}

function loginSuccess(isSuccess, user) {

console.log('success');

return {

type: types.LOGIN_IN_DONE,

user: user,

}

}

function loginError(isSuccess) {

console.log('error');

return {

type: types.LOGIN_IN_ERROR,

}

}

5.(设定消息的具体处理过程)reducers文件夹内新建loginReducer文件,用来处理登录过程中的state变化


'use strict';

import * as types from '../constants/loginTypes'; // 导入事件类别,用来做事件类别的判断

// 初始状态

const initialState = {

status: '点击登录',

isSuccess: false,

user: null,

}

// 不同类别的事件使用switch对应处理过程

export default function loginIn(state=initialState, action) {

switch (action.type) {

case types.LOGIN_IN_DOING:

return {

...state,

status: '正在登陆',

isSuccess: false,

user: null,

}

break;

case types.LOGIN_IN_DONE:

return {

...state,

status: '登陆成功',

isSuccess: true,

user: action.user,

}

break;

case types.LOGIN_IN_ERROR:

return {

...state,

status: '登录出错',

isSuccess: true,

user: null,

}

break;

default:

return state;

}

}

6).项目内可能并不是只有一个redux操作逻辑,现在给所有的reducer建立一个统一的入口

reducers文件夹内新建index.js文件,作为统一入口;

(由于本篇文章是demo写好后整理的,所以现在这里不应该有counterReducer,大家在参考本文时,这里只写login的内容即可)


'use strict';

import { combineReducers } from 'redux';

import loginIn from './loginReducer'; // 导入登录的redux处理过程

const rootReducer = combineReducers({ // 将所有的redux处理逻辑包装在一起

loginIn: loginIn,

});

export default rootReducer; // 导出,作为统一入口

7).创建项目中的store,用来管理所有的state

store文件夹内新建ConfigureStore.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 configureStore(initialState) {

const store = createStoreWithMiddleware(rootReducer, initialState)

return store;

}

8).现在action,reducer,store都存在了,按照我另一篇原理分析内的非视图部分已基本完成.

接下来我们在处理视图部分,即Provider.在这里我个人习惯从外层往内写.先写Provider外壳,并将整个APP包裹在内;

src文件夹内,新建Root.js文件,该文件内实现Provider对视图部分的包裹


import React, { Component } from 'react';

import { Provider } from 'react-redux';

import configureStore from './store/ConfigureStore';

import App from './container/App';// app的入口

const store = configureStore();

export default class Root extends Component {  

    render() {    

        return (

            <Provider store={store}>

                <App />

           </Provider>

        ) 

    }

}

import App from './container/App';这里对应的是 app的入口 写到这里的时候,本文件还没有实现

9).实现视图的部分代码

container文件夹内新建App.js文件,作为整个app的入口;

此处使用了react-navigation用来管理页面;


import React, { Component } from 'react';

import {

View,

Text,

} from 'react-native';

import { StackNavigator } from 'react-navigation';

import LoginPage from '../pages/LoginPage'

import MainPage from '../pages/MainPage'

const App = StackNavigator({

Login: { screen: LoginPage },

Main: { screen: MainPage},

});

export default App

10.实现页面(注意此处有很关键的一步,需要在页面内实现组件和store的关联,之所以能够实现不同的组件关联不同的state也是在这一步进行的)

此处代码量较多,只粘贴关键代码


红框部分:多reducer内选择不同的reducer

class LoginPage extends Component { 

 static navigationOptions = {    title: 'LoginPage',  };  

shouldComponentUpdate(nextProps, nextState) {    

// 登录完成,切成功登录   

 if (nextProps.status === '登陆成功' && nextProps.isSuccess) {      

this.props.navigation.dispatch(resetAction)     

 return false;   

 }    

return true;  

 render() {    

const { login } = this.props;    

return(

/*...components*/

 }

}

export default connect(

(state) => ({

status: state.loginIn.status,

isSuccess: state.loginIn.isSuccess,

user: state.loginIn.user,

}),

(dispatch) => ({

login: () => dispatch(loginAction.login()),

})

)(LoginPage)

11).请大家自行实现加减法部分的逻辑并将其关联到对应的页面内.

1.设定时间的所有处理类别; type

2.事件预处理过程; action

3.事件处理过程; reducer

4.通过reducer统一入口导出供外部使用;

5.实现视图pages并将其与逻辑部分绑定到一起;connect

可查阅demo代码

希望本文对大家有所帮助

有问题欢迎大家留言评论,会尽快回复的

react-native