在小程序里使用 Redux 进行状态管理, Redux 是一个前端状态管理的容器,对于构建大型应用,对里面共享数据、状态的管理非常方便,学过 React 的同学对它应该不陌生,如果还不了解的同学,不如进服瞧一瞧;
wepy 框架本身是支持 Redux 的,我们在构建项目的时候,将 是否安装 Redux 选择 y 就好了,会自动安装依赖,运行项目后看官方给的 demo 确实是可以做到的,但是官方文档里却对这一块只字不提,经过我自己尝试了一波,这才稍微摸清了它的使用方式,赶紧拿来与你们分享~
注意了,接下来划重点了~
运行我们的项目,发现官网已经给了我们一些 Redux 的使用方法,实际上主要是放在 store文件夹下面了,我们现在来一探究竟~
入口文件 index.js ,里面主要是 初始化 Redux , 其中 promiseMiddleware 是一个中间件,方便后面 action 做异步处理~ reducers 是一个纯函数,用于接受 Action 和当前 State作为参数,返回一个新的 State ~
import { createStore , applyMiddleware } from 'redux' import promiseMiddleware from 'redux-promise' import reducer from './reducers' const Store = createStore( reducer , applyMiddleware(promiseMiddleware) ) export default configStore => Store
剩下三个文件夹分别是 types reducers 和 actions ,其中 types 用于定义我们要触发的 action 的名称,也就是表示 action 的名称,这里我定义了 counter 和 list 两个 types ,内容分别如下:
counter.js
export const INCREMENT = 'INCREMENT' export const DECREMENT = 'DECREMENT' export const ASYNC_INCREMENT = 'ASYNC_INCREMENT'
list.js
export const ADD = 'ADD' export const REMOVE = 'REMOVE'
最后通过 types 文件夹的入口文件 index.js 将他们暴露出去~
export * from './counter' export * from './list'
reducers 文件件存放我们的纯函数,用来更改我们的状态 , 他也有一个入口文件 index.js,定义如下:
import { combineReducers } from 'redux' import counter from './counter' import list from './list' export default combineReducers({ counter , list })
首先将 counter 和 list 的分别引入进来,通过 redux 定义的 combineReducers 函数,将所有的 reducers 合并成一个整体,方便我们后面对其进行管理!
那么 counter 和 list 对应的 reducer 分别是 什么样的?我们直接看代码:
counter.js
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
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 如下:
index.js
export * from './counter'
很简单,只需要将所需的 action 导出即可~
这个里面我只定义了 counter 的 action , 也就是为了刚才异步数据 asyncNum 准备的~
counter.js
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 的容器~
接下来,就是展示它怎么使用的时候了~
我们创建一个 index.wpy 的文件,这里我把代码直接贴出来,然后慢慢来分析看看~
代码如下:
<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>
点一点看,发现卧槽,很牛逼,有木有~
ok~ 我们一起看看上面的代码是怎么做的~
样式结构方面我们这里不做讨论,主要看 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 属性值上。
全国7x24小时客服热线
所有故障均24小时内解决
项目一次性收费安心
技术人员均从业5年以上
通过技术营销传播企业服务价值
丰富的行业实战经验积累
基于需求研发多款产品
针对需求提供精细化服务