小程序使用Redux状态管理

Redux状态管理
Redux 是一个前端状态管理的容器,对于构建大型应用,对里面共享数据、状态的管理非常方便
wepy 框架本身是支持 Redux 的,我们在构建项目的时候,将是否安装 Redux 选择 y 就好了,会自动安装依赖

入口文件index.js

入口文件index.js,里面主要是 初始化Redux, 其中promiseMiddleware是一个中间件,方便后面action做异步处理reducers是一个纯函数,用于接受Action和当前State作为参数,返回一个新的State

1
2
3
4
5
6
7
8
import { createStore, applyMiddleware } from 'redux'
import promiseMiddleware from 'redux-promise'
import rootReducer from './reducers'

export default function configStore () {
const store = createStore(rootReducer, applyMiddleware(promiseMiddleware))
return store
}

文件夹types reducers 和 actions

其中types用于定义我们要触发的action的名称,也就是表示action的名称,这里我定义了counterlist两个types

types

counter.js

1
2
3
4
5
export const INCREMENT = 'INCREMENT'

export const DECREMENT = 'DECREMENT'

export const ASYNC_INCREMENT = 'ASYNC_INCREMENT'

list.js

1
2
3
export const ADD = 'ADD'

export const REMOVE = 'REMOVE'

通过types文件夹的入口文件index.js将他们暴露出去

index.js

1
2
export * from './counter'
export * from './list'

reducers

reducers文件件存放我们的纯函数,用来更改我们的状态 , 他也有一个入口文件index.js

index.js

1
2
3
4
5
6
7
8
import { combineReducers } from 'redux'
import counter from './counter'
import list from './list'

export default combineReducers({
counter,
list
})

首先将counter引入进来,通过redux定义的combineReducers函数,将所有的reducers合并成一个整体,方便我们后面对其进行管理

counter.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
import { handleActions } from 'redux-actions'
import { INCREMENT, DECREMENT, ASYNC_INCREMENT } from '../types/counter'

const defaultState = {
num: 0 ,
asyncNum: 0
}

export default handleActions({
[INCREMENT] (state) {
return {
...state,
num: state.num + 1
}
},
[DECREMENT] (state) {
return {
...state,
num: state.num - 1
}
},
[ASYNC_INCREMENT] (state, action) {
return {
...state,
asyncNum: state.asyncNum + action.payload
}
}
}, defaultState)

介绍一下counter.js里面的reducer, 首先引入了handleActions方法用来创建actions, 它将多个相关的reducer写在一起也是 ,方面后期维护,也方便后期通过dispatch来调用他们更改state里面的状态,它主要接收两个参数,第一个参数时候个大对象,里面存放多个reducer, 第二个参数是初始化的时候state的状态值,因此,我们一开始就定义了defaultState;

接着,我们看看里面的reducer, 分别定义了INCREMENT、 DECREMENT 和 ASYNC_INCREMENT三个reducer,前两个比较简单,分别是对state里面的num值进行加减操作 , 最后一个是通过action.payload的值来对asyncNum的值进行异步操作的,具体怎么做到的,我们一会再看

list.js里定义的reducer跟上面类似

list.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import { handleActions } from 'redux-actions'
import { ADD , REMOVE } from '../types/list'

const defaultState = [
{
title : '吃饭' ,
text : '今天我要吃火锅'
},
{
title : '工作' ,
text : '今天我要学习Redux'
}
]

export default handleActions({
[ADD]( state , action ){
state.push(action.payload)
return [...state]
},
[REMOVE]( state , action ){
state.splice( action.payload , 1 );
return [ ...state ]

}
},defaultState)

actions

index.js

1
export * from './counter'

counter.js

1
2
3
4
5
6
7
8
9
10
import { ASYNC_INCREMENT } from '../types/counter'
import { createAction } from 'redux-actions'

export const asyncInc = createAction(ASYNC_INCREMENT, () => {
return new Promise(resolve => {
setTimeout(() => {
resolve(1)
}, 1000)
})
})

这里跟reducer里面的要区分,这里是可以对数据进行一系列处理的,我们通过createAction创建一个action, 该方法主要有两个参数,第一个参数type表示action的类型,第二个参数payloadCreator是一个function,处理并返回需要的payload;如果空缺,会使用默认方法。这里是延迟 1s 后返回一个 1

ok,到此为止,已经基本完成了一个redux的容器,接下来,就是展示它怎么使用的时候了

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
<template lang="wxml">
<view class="container">
<text>同步{{ num }}</text>
<text>异步{{ asyncNum }}</text>
<button @tap="increment" type="primary">加一</button>
<button @tap="decrement" type="primary">减一</button>
<button @tap="asyncIncrement" type="primary">异步加一</button>

<button @tap="addList">添加</button>

<view class="box">
<view class="item" wx:for-items="{{ todoList }}" wx:key="index">
<view class="title">{{ item.title }}</view>
<view class="content">{{ item.text }}</view>
<button type="primary" class="delete" @tap="delete({{index}})">删除</button>
</view>
</view>

</view>

</template>

<script>
import wepy from 'wepy'
import { connect } from 'wepy-redux'
import { INCREMENT , DECREMENT } from '../store/types/counter'
import { asyncInc } from '../store/actions'

@connect({
num(state){
return state.counter.num;
},
asyncNum(state){
return state.counter.asyncNum;
}
},{
increment : INCREMENT ,
decrement : DECREMENT ,
asyncIncrement : asyncInc
})

export default class Index extends wepy.page {

components = {}

computed = {
todoList(){
return wepy.$store.getState().list;
}
}

methods = {
delete(index){
wepy.$store.dispatch({
type : 'REMOVE',
payload : index
})
},
addList(){
wepy.$store.dispatch({
type : 'ADD' ,
payload : {
title : '学习' ,
text : '好好学习'
}
})
}

onLoad () {
console.log(wepy.$store.getState())
}
}
</script>


<style lang="less">
text{
display: block;
text-align: center;
margin: 10px auto;
}
button{
width: 90%;
display: block;
margin: 10px auto;
}

.item{
display: flex;
align-items: center;
text-align: center;
padding: 0 15px;
.title{
font-size: 14px;
line-height: 20px;
margin: 10px auto;
}
.content{
font-size: 15px;
flex: 1;
}

.delete{
width: 70px;
height: 40px;
line-height: 40px;
}
}
</style>

主要看 js 部分,其中import { INCREMENT , DECREMENT } from '../store/types/counter'import { asyncInc } from '../store/actions'分别表示从counteractions导出所需的action

我们重点看看 从wepy-redux中 引入的connect,这个connect很关键,它是连接 组件 和 状态 的桥梁,主要用法是@connect(states, actions)

  • states: 访问state上的值,可以是数组或者对象,如果是对象的话,则包含的是K-VV可以是函数还可以是字符串,如果是字符串的话则默认获取state[V], 否则的话则是使用返回值;而对于如果是数组的话(数组中的项只能为字符串),则认为是相同的K-V对象结构。states最终会附加到组件的computed属性值上。

  • actions: 只能传入对象,对象的K-V结构,如果V是字符串的话,则直接会distatch如下的结构:

    1
    2
    3
    4
    5
    6
    7
    // args 就是调用传入参数
    {
    type: val,
    // 修正一般情况下的参数 一般支持只传一个参数
    // 如果真的是多个参数的话 那么 payload 就是参数组成的数组
    payload: args.length > 1 ? args : args[0]
    }

如果是一个函数fn,则会dispatch(val.apply(store, args)),否则的话则直接dispatch(V)

这里,我们定义的加一减一异步加一操作直接映射到INCREMENT、DECREMENT、asyncInc上,也就是相当于直接dispacth对应的操作,对数据进行变更

当然,我们也可以手动调用容器的dispatch方法对数据进行修改,我们的添加删除就是这么做的, 点击删除按钮,我们直接dispatch列表中的ADD action

1
2
3
4
wepy.$store.dispatch({ type : 'ADD' , payload : {
title : '学习' ,
text : '好好学习'
}})