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
的名称,这里我定义了counter
和list
两个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'
分别表示从counter
和actions
导出所需的action
我们重点看看 从wepy-redux
中 引入的connect
,这个connect
很关键,它是连接 组件 和 状态 的桥梁,主要用法是@connect(states, actions)
states
: 访问state
上的值,可以是数组或者对象,如果是对象的话,则包含的是K-V
对V
可以是函数还可以是字符串,如果是字符串的话则默认获取state[V]
, 否则的话则是使用返回值;而对于如果是数组的话(数组中的项只能为字符串),则认为是相同的K-V
对象结构。states
最终会附加到组件的computed
属性值上。
actions
: 只能传入对象,对象的K-V
结构,如果V
是字符串的话,则直接会distatch
如下的结构:
1 2 3 4 5 6 7
| { type: val, 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 : '好好学习' }})
|