1.Redux的基本用法
前言
说明: 本文只针对移动端的Redux的基本用法进行描述。
- 希望这一篇文章,就能帮助你搞定redux的基本用法,甚至不用再去查阅其他文档。
- 因为我个人脑子比较笨,查阅了很多文档,看了不少视频资料才理解了。
2. 原理阐述(个人根据对官方文档理解的阐述)
- 关键词 store、action、reducer
- store是全局唯一的(在服务端可能有多个,但是我们在移动开发中,只有一个),它的作用是用来存储数据。
- action,翻译过来就是“动作,行动”的意思。 在我们这里,我们可以理解为对一种行动的描述,包括名字,要做的事情,参数等。
- reducer,翻译过来就是“减速器”的意思,个人理解为缓冲者可能比较妥当。
(1)意思是,当有人发送一个action,会给到reducer来处理,或者作为一个缓冲地带,来进行一些数据处理。
(2)处理后的数据会存储到store中,而且这是唯一可以改变store中的数据方法。 - 数据的使用
(1)get方法,在UI界面中,数据源通过get方法获取
(2)set方法,在这里没有直接的set方法,要修改数据,通过dispatch来set (dispatch翻译过来就是发送,派遣,邮寄的意思,我们可以理解为发送快递的方式)
(3)这里通过dispatch发送的包裹,就是action(这里有一些我们想修改的数据相关内容)
- 数据流向图(单一数据流向)
3.脑海里大概有个上面的数据流向图即可,先看下面的代码(最好自己也写一遍,会加深印象,有助于理解)
- 文件目录结构如下
一. 我们先搭建一个简单的界面(View1–index.js)
import React, { Component } from 'react';
import {
Button,
Text,
View,
StyleSheet
} from 'react-native';
import { connect } from 'react-redux';
import * as uiAction from '../Redux/action/uiActions';
class Home extends Component {
constructor(props) {
super(props);
this.state = {
name: "张三",
age: 18
}
}
render() {
return (
<View style = {styles.container}>
<Text>Hello, my name is { this.state.name },I'm {this.state.age} years old</Text>
<Button
title='增加年龄'
onPress={() => {
}}
/>
<Button
title='减少年龄'
onPress={() => {
}}
/>
<Button
title='修改姓名'
onPress={() => {
}}
/>
</View>
)
}
}
export default Home
const styles = StyleSheet.create({
container: {
justifyContent: 'center',
alignItems: 'center',
flex: 1
}
})
二. 我们想做的事情很简单
- 点击增加或减少年龄,修改界面的年龄显示
- 点击修改名字,修改界面的名字显示
- 那么我们如何通过Redux来实现呢?我们分为几个步骤。
三.Redux的使用步骤(本文核心内容)
开始之前,我们导入依赖库
一次性导入依赖库:
yarn add immutable \
react-redux \
redux \
redux-logger \
redux-promise-middleware \
redux-thunk
1.step one
- 创建action、reducer、store
(1) 我们创建actionType.js文件
import { ActionType } from 'redux-promise-middleware';
/*
* 编程规范建议:
* 1. 我们的每个action大类,个人觉得以ActionXX来开头命名,
* 使用的时候更能体现见名知意。
* 2. 里面对具体某个action,个人觉得以K开头,更能区分代表是具体action的key值
*/
export const actionType = {
ActionUI: {
KaddAge: "addAge",
KdecrementAge: "decrementAge",
KmodifyName: "modifyName"
}
}
(2) 我们创建uiActions.js文件
import { actionType } from "./actionType";
/**
* 通常,根据action类型来命名函数
*/
/*
* type:表示是action的具体类型,我们可以直接使用我们上个actionType
* payload: 表示参数,也是外面传过来的参数
* 在这里,addAge函数,就是dispatch发送的包裹了
*/
export function addAge(age) {
return {
type: actionType.ActionUI.KaddAge,
payload: age
}
}
export function decrementAge(age) {
return {
type: actionType.ActionUI.KdecrementAge,
payload: age
}
}
export function modifyName(name) {
return {
type: actionType.ActionUI.KmodifyName,
payload: name
}
}
(3) 创建所有action的入口函数,index.js,我们这里暂时没有创建
export * from './uiAction'
export * from './xxAction' // 如果有别的action,可以统一放到这里
export * from './xxxAction'
2.step two
(1)创建uiReducer.js文件
import { actionType } from "../action/actionType";
import { fromJS } from "immutable";
/**
* 初始状态,不可变的,这里的state的的key,都是在UI界面中的state可以直接调用的
* 比如:界面一个文本的名字内容,显示什么,就是直接用这里的myName
*/
function initialState() {
return fromJS({
myName: "张三",
myAge: 18
});
}
/**
* 这里为了代码的简洁性、可读性、维护性、解耦性
* 我们不要写成switch语句,否则一个函数的行数很容易超过50行
* 个人不建议一个函数的行数超过50行
*
* 我们这里根据prototype来定义多个函数,只是参数的类型不同
* 有点像C++里的函数重载
*/
export default function reducer(state = initialState(), action) {
if (typeof reducer.prototype[action.type] === 'function') {
return reducer.prototype[action.type](state, action);
} else {
return state;
}
}
reducer.prototype[actionType.ActionUI.KaddAge] = (state, action) => {
return state.set('myAge', action.payload);
}
reducer.prototype[actionType.ActionUI.KdecrementAge] = (state, action) => {
return state.set('myAge', action.payload);
}
reducer.prototype[actionType.ActionUI.KmodifyName] = (state, action) => {
return state.set('myName', action.payload);
}
(2)创建reducer的入口函数,index.js
import ui from './uiReducer';
import otherReducer from './otherReducer'; // 假如还有其他reducer
import { combineReducers } from 'redux';
export default combineReducers({
ui,
otherReducer // 如果还有其他reducer,就这样类似往里面添加
});
3.step three
创建store,也是唯一的store
import { applyMiddleware, createStore } from "redux";
import { createLogger } from "redux-logger";
import thunk from "redux-thunk";
import promise from "redux-promise-middleware";
import reducer from '../reducer';
// 分为调试环境 和 release环境,调试环境就有log日志
const middleware = __DEV__ ?
applyMiddleware(promise, thunk, createLogger())
:
applyMiddleware(promise, thunk)
export default createStore(reducer, middleware)
- 到此为止,我们已经完成了80%了。如果能看到这里,提前恭喜一下你!
4.step four
- 现在需要把redux和UI界面串联起来
- 对于下面的没有使用过redux的UI界面,我们开始改造
class Home extends Component {
constructor(props) {
super(props);
this.state = {
name: "张三",
age: 18
}
}
render() {
return (
<View style = {styles.container}>
{...}
</View>
)
}
}
export default Home
(1)去掉constructor
(2)导入connect,导入把export default Home改为:
import { connect } from 'react-redux';
export default connect((state) => {
return {
person: state.ui
};
})(Home);
(3) 用Provider包裹整个APP
import React from 'react';
import { Provider } from 'react-redux';
import store from './smallDemo/Redux/store/store';
const ReduxApp = () => (
<Provider store={store}>
<App />
</Provider>
)
AppRegistry.registerComponent(appName, () => ReduxApp);
(4) dispatch的使用方法
render() {
return (
<View style = {styles.container}>
<Text>Hello, my name is { this.props.person.get('myName') },I'm {this.props.person.get('myAge')} years old</Text>
<Button
title='增加年龄'
onPress={() => {
this.props.dispatch(
uiAction.addAge(this.props.person.get('myAge') + 20)
)
}}
/>
<Button
title='减少年龄'
onPress={() => {
this.props.dispatch(
uiAction.addAge(this.props.person.get('myAge') - 10)
)
}}
/>
<Button
title='修改姓名'
onPress={() => {
this.props.dispatch(
uiAction.modifyName("zhangsan")
)
}}
/>
</View>
)
}
- 到此为止,我们已经阐述完了整个redux的基本使用方法
- end~ Thanks!