react-native项目中从零开始使用redux
本文主要是以我的另一篇文章的思维过程来操作,希望大家使用后可以记住整个过程,从而活学活用,使用到自己的项目中.
参考文章:react-native中使用redux的原理分析及demo
demo地址:github.com/NextChampion/react-native-redux-navigation-example
效果图
效果图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内选择不同的reducerclass 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代码
希望本文对大家有所帮助
有问题欢迎大家留言评论,会尽快回复的