前陣子一直在做小程序開(kāi)發(fā),采用的是官方給的框架 wepy , 如果還不了解的同學(xué)可以去他的官網(wǎng)查閱相關(guān)資料學(xué)習(xí);不得不說(shuō)的是,這個(gè)框架確相比于傳統(tǒng)小程序開(kāi)發(fā)模式確實(shí)方便很多,它的語(yǔ)法 Vue 的語(yǔ)法很像,可以實(shí)現(xiàn)組件化開(kāi)發(fā),方面后面代碼的調(diào)整和維護(hù)...但是?。∵@個(gè)框架的坑也不是一點(diǎn)點(diǎn),開(kāi)發(fā)的時(shí)候總會(huì)遇到奇奇怪怪的問(wèn)題,自己去踩吧,這樣你才能進(jìn)步~~ 廢話(huà)了這么多,咳咳,上面的都不是我們要討論的重點(diǎn),我們今天的重點(diǎn)是—在小程序里使用 Redux 進(jìn)行狀態(tài)管理, Redux 是一個(gè)前端狀態(tài)管理的容器,對(duì)于構(gòu)建大型應(yīng)用,對(duì)里面共享數(shù)據(jù)、狀態(tài)的管理非常方便,學(xué)過(guò) React 的同學(xué)對(duì)它應(yīng)該不陌生,如果還不了解的同學(xué),不如進(jìn)服瞧一瞧; wepy 框架本身是支持 Redux 的,我們?cè)跇?gòu)建項(xiàng)目的時(shí)候,將 是否安裝 Redux 選擇 y 就好了,會(huì)自動(dòng)安裝依賴(lài),運(yùn)行項(xiàng)目后看官方給的 demo 確實(shí)是可以做到的,但是官方文檔里卻對(duì)這一塊只字不提,經(jīng)過(guò)我自己嘗試了一波,這才稍微摸清了它的使用方式,趕緊拿來(lái)與你們分享~ 注意了,接下來(lái)劃重點(diǎn)了~ 具體實(shí)現(xiàn)運(yùn)行我們的項(xiàng)目,發(fā)現(xiàn)官網(wǎng)已經(jīng)給了我們一些 Redux 的使用方法,實(shí)際上主要是放在 store文件夾下面了,我們現(xiàn)在來(lái)一探究竟~ step1入口文件 index.js ,里面主要是 初始化 Redux , 其中 promiseMiddleware 是一個(gè)中間件,方便后面 action 做異步處理~ reducers 是一個(gè)純函數(shù),用于接受 Action 和當(dāng)前 State作為參數(shù),返回一個(gè)新的 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 step2剩下三個(gè)文件夾分別是 types reducers 和 actions ,其中 types 用于定義我們要觸發(fā)的 action 的名稱(chēng),也就是表示 action 的名稱(chēng),這里我定義了 counter 和 list 兩個(gè) types ,內(nèi)容分別如下: 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' 最后通過(guò) types 文件夾的入口文件 index.js 將他們暴露出去~ export * from './counter' export * from './list' step3reducers 文件件存放我們的純函數(shù),用來(lái)更改我們的狀態(tài) , 他也有一個(gè)入口文件 index.js,定義如下: import { combineReducers } from 'redux' import counter from './counter' import list from './list' export default combineReducers({ counter , list }) 首先將 counter 和 list 的分別引入進(jìn)來(lái),通過(guò) redux 定義的 combineReducers 函數(shù),將所有的 reducers 合并成一個(gè)整體,方便我們后面對(duì)其進(jìn)行管理! 那么 counter 和 list 對(duì)應(yīng)的 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 方法用來(lái)創(chuàng)建 actions , 它將多個(gè)相關(guān)的 reducer 寫(xiě)在一起也是 ,方面后期維護(hù),也方便后期通過(guò) dispatch來(lái)調(diào)用他們更改 state 里面的狀態(tài),它主要接收兩個(gè)參數(shù),第一個(gè)參數(shù)時(shí)候個(gè)大對(duì)象,里面存放多個(gè) reducer , 第二個(gè)參數(shù)是初始化的時(shí)候 state 的狀態(tài)值,因此,我們一開(kāi)始就定義了 defaultState ; 接著,我們看看里面的 reducer , 分別定義了 INCREMENT 、 DECREMENT 和 ASYNC_INCREMENT 三個(gè) reducer ,前兩個(gè)比較簡(jiǎn)單,分別是對(duì) state 里面的 num 值進(jìn)行 加減操作 , 最后一個(gè)是通過(guò) action.payload 的值來(lái)對(duì) asyncNum 的值進(jìn)行異步操作的,具體怎么做到的,我們一會(huì)再看~ list.js 里定義的 reducer 跟上面類(lèi)似,我就不一一介紹了,直接貼代碼即可~ list.js import { handleActions } from 'redux-actions' import { ADD , REMOVE } from '../types/list' const defaultState = [ { title : '吃飯' , text : '今天我要吃火鍋' }, { title : '工作' , text : '今天我要學(xué)習(xí)Redux' } ] export default handleActions({ [ADD]( state , action ){ state.push(action.payload) return [...state] }, [REMOVE]( state , action ){ state.splice( action.payload , 1 ); return [ ...state ] } },defaultState) step4我們終于走到這一步了,到這里,你已經(jīng)離預(yù)期不遠(yuǎn)啦,就剩一個(gè) actions 文件件了,毫不例外,入口文件 index.js 如下: index.js export * from './counter' 很簡(jiǎn)單,只需要將所需的 action 導(dǎo)出即可~ 這個(gè)里面我只定義了 counter 的 action , 也就是為了剛才異步數(shù)據(jù) asyncNum 準(zhǔn)備的~ 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 里面的要區(qū)分,這里是可以對(duì)數(shù)據(jù)進(jìn)行一系列處理的,我們通過(guò) createAction 創(chuàng)建一個(gè) action , 該方法主要有兩個(gè)參數(shù),第一個(gè)參數(shù) type 表示 action 的類(lèi)型,第二個(gè)參數(shù) payloadCreator 是一個(gè) function ,處理并返回需要的 payload ;如果空缺,會(huì)使用默認(rèn)方法。這里我們是延遲 1s 后返回一個(gè) 1 ; ok,到此為止,你已經(jīng)基本完成了一個(gè) redux 的容器~
接下來(lái),就是展示它怎么使用的時(shí)候了~ step5我們創(chuàng)建一個(gè) index.wpy 的文件,這里我把代碼直接貼出來(lái),然后慢慢來(lái)分析看看~ 代碼如下: <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 : '學(xué)習(xí)' , text : '好好學(xué)習(xí)' }}) } } 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> 不出意外,運(yùn)行后,你的小程序的界面會(huì)跟下面一樣————丑~
點(diǎn)一點(diǎn)看,發(fā)現(xiàn)臥槽,很牛逼,有木有~ ok~ 我們一起看看上面的代碼是怎么做的~ 樣式結(jié)構(gòu)方面我們這里不做討論,主要看 js 部分,其中 import { INCREMENT , DECREMENT } from '../store/types/counter' 和 import { asyncInc } from '../store/actions'分別表示從 counter 和 actions 導(dǎo)出所需的 action 我們重點(diǎn)看看 從 wepy-redux 中 引入的 connect ,這個(gè) connect 很關(guān)鍵,它是連接 組件 和 狀態(tài) 的橋梁,主要用法是 @connect(states, actions) ~
|