微信小程序没有提供Promise版本的异步api;
把微信小程序异步api转化为Promise,用于处理redux中的异步action;
把微信小程序原生网络请求 request 转换为 promise,toPromise.js

const toPromise = (wx) => {
return (method) => {
return (option) => {
return new Promise ((resolve, reject) => {
wx[method]({
...option,
success: (res) => { resolve(res) },
fail: (err) => { reject(err) }
})
})
}
}
}
export default toPromise

设置 http 请求的三个状态,“开始请求”、“收到请求"和"请求失败”。
http3Steps.js

export const REQUSET_BEGIN = 'REQUEST_BEGIN'; // 开始网络请求
export const RECEIVED = 'RECEIVED'; // 收到请求
export const REQUEST_FAILED = 'REQUEST_FAILED'; // 请求失败
export const requestBegin = (requestName) => ({
type: REQUSET_BEGIN + requestName
})
export const received = (requestName, res) => ({
type: RECEIVED + requestName,
res
})
export const requestFailed = (requestName, err) => ({
type: REQUEST_FAILED + requestName,
err
})

action.js

import {
requestBegin,
received,
requestFailed
} from './http3Steps'
import toPromise from './toPromise.js'
const toPromiseWx = toPromise(wx)
const request = toPromiseWx('request')

//网络请求action
//根据redux官网的介绍,它应该是一个Promise,但是微信小程序没有提供Promise版本的异步api,需要使用上面提到的工具库

export const fetch = (requestName, option) => {
return (dispatch) => {
dispatch(requestBegin(requestName)) //请求开始,更新state状态
if(requestName=='_USER_LOGOUT') {
// 用户退出登录时,清空缓存数据
dispatch(requestFailed(requestName, "退出登录"));
return;
};
return request(option)
.then(
(res) => {
dispatch(received(requestName, res.data.payload));
return res
}, //请求成功,把返回的信息在state中更新
(err) => {
dispatch(requestFailed(requestName, err))
} //请求失败,把失败的信息在state中更新
)
}
}

export const FZ_CONFIG_DATA = '_FZ_CONFIG_DATA'; // 复诊的配置信息
export const USER_INFO_DATA = "_USER_INFO_DATA"; // 用户信息
export const NEW_PRESCRIPTION = "_NEW_PRESCRIPTION"; // 最新处方
export const GET_BANNER = "_GET_BANNER"; // 首页的banner
export const USER_LOGOUT = "_USER_LOGOUT"; // 推出登陆

这里可以把定义的常量单独放在另一个文件里。
在电脑本地创建一个空的文件夹,然后安装 redux、redux-thunk 和 redux-logger。在 node_modules 中选出对应 redux、redux-thunk 和 redux-logger 文件夹下的 dist 文件中的 redux.js、redux-thunk.js、redux-logger.js 复制到小程序项目下的 modules 文件夹内。

新建文件reducer.js

import { FZ_CONFIG_DATA } from './action.js' // 常量
import { REQUSET_BEGIN, RECEIVED, REQUEST_END } from './action.js'
import { combineReducers } from "../module/redux";

//这是处理本例中异步的reducer
const preState = {}

// 平台的配置数据
export const disposeFetch = (state = preState, action) => {
switch (action.type) {
case REQUSET_BEGIN + FZ_CONFIG_DATA:
return {
...state,
status: 'REQUEST_BEGIN',
}
case RECEIVED + FZ_CONFIG_DATA:
return {
...state,
status: 'RECEIVED',
res: action.res
}
case REQUEST_END + FZ_CONFIG_DATA:
return {
...state,
status: 'REQUEST_END',
err: action.err
}
case REQUSET_BEGIN + USER_LOGOUT:
return {
status: 'USER_LOGOUT',
}
default:
return state
}
}
// 用户信息
export const disposeUserInfo = (state = preState, action) => {
switch (action.type) {
case REQUSET_BEGIN + USER_INFO_DATA:
return {
...state,
status: 'REQUEST_BEGIN',
}
case RECEIVED + USER_INFO_DATA:
return {
...state,
status: 'RECEIVED',
res: action.res
}
case REQUEST_END + USER_INFO_DATA:
return {
...state,
status: 'REQUEST_END',
err: action.err
}
case REQUSET_BEGIN + USER_LOGOUT:
wx.removeStorageSync('tokenId')
wx.removeStorageSync('userData')
wx.removeStorageSync('openid')
return {
status: 'USER_LOGOUT',
}
default:
return state
}
}
// 首页的最新数据
export const disposeNewPrescription = (state = {}, action) => {
console.log(action)
switch (action.type) {
case REQUSET_BEGIN + NEW_PRESCRIPTION:
return {
...state,
status: 'REQUEST_BEGIN',
}
case RECEIVED + NEW_PRESCRIPTION:
return {
...state,
status: 'RECEIVED',
res: action.res.list
}
case REQUEST_END + NEW_PRESCRIPTION:
return {
...state,
status: 'REQUEST_END',
err: action.res
}
case REQUSET_BEGIN + USER_LOGOUT:
return {
status: 'USER_LOGOUT',
}
default:
return state
}
}
// 首页的banner数据
export const disposeBanner = (state = {}, action) => {
switch (action.type) {
case REQUSET_BEGIN + GET_BANNER:
return {
...state,
status: 'REQUEST_BEGIN',
}
case RECEIVED + GET_BANNER:
return {
...state,
status: 'RECEIVED',
res: action.res
}
case REQUEST_END + GET_BANNER:
return {
...state,
status: 'REQUEST_END',
err: action.err
}
default:
return state
}
}
//按照state的结构组合起来
export default combineReducers({
asyncData: disposeFetch, // 平台的配置信息
userData: disposeUserInfo, // 用户信息
newPrescription: disposeNewPrescription, // 首页的最新数据
banner: disposeBanner, // 首页的banner
})

最后在 app.js 中添加 store 相关的代码,或者是单独创建 store.js 文件也可以;

app.js

import reducer from './reducer.js'
import { createStore, applyMiddleware } from './module/redux'
import logger from './module/redux-logger'
import thunkMiddleware from './module/redux-thunk'
//创建redux store
export const store = createStore(
reducer,
applyMiddleware(
logger,//用于控制台state调试
thunkMiddleware//用于处理异步action
)
)

App({
...
})

之所以在小程序中引入 redux 来做状态管理,无非就是在小程序频繁切换的几个页面中减少部分的网络请求,在性能上得到一定的优化。
例如在首页中引入 redux:

home.js

import {
store
} from '../../app';
import {
fetch,
FZ_CONFIG_DATA,
USER_INFO_DATA,
NEW_PRESCRIPTION,
GET_BANNER,
} from '../../action/index';
const {
dispatch,
subscribe,
getState
} = store;

Page({
/**
* 生命周期函数--监听页面加载
*/
onLoad: function () {
const store_data = store.getState().userData;
console.log("redux======",store_data)
//在onLoad函数中订阅state的更新
//如果state变化,对应ui就会更新
subscribe(() => {
const {
asyncData: {
status
}
} = getState();
});

// 获取用信息
dispatch(fetch(USER_INFO_DATA, {
url: serverUrl + "/ncmsSysXcxuser/login",
data: {
openid: wx.getStorageSync('openid')
},
header: {
'content-type': 'application/x-www-form-urlencoded',
"tokenid": wx.getStorageSync("tokenId")
},
method: "POST",
})).then((result) => {
console.log(result)
})
},
})

这就是原生小程序引入 redux 的流程。