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