1. 概要
微信小程式的開發體驗類似vue和react,但是卻沒有提供全域性狀態管理的機制,所以狀態的共享只能通過屬性傳遞的方式來實現。這種做法在小規模的應用中尚可以滿足開發效率,但是在複雜的應用中元件的巢狀層次很深,屬性傳遞的路徑過長。
於是我就想利用小程式Page中的data物件來構建一個全域性store,這個store滿足一下幾點需求:
- store可以被當前頁面中任意一個元件訪問,並且這種訪問時直接的而不是通過屬性傳遞。
- 全域性store對於元件是相應式的,也就是說store的變化可以使元件發生重繪。
- 頁面和元件都可以修改store的狀態,並且這種修改不破壞原來的響應式。
- 提供類似Vuex的開發體驗,減小學習成本。
先附上原始碼 github地址
2. 使用
我們先跳過原理來看使用方法。
2.1 安裝
將Store.js放入微信小程式專案的資料夾中,例如/lib/Store.js。
2.2 建立Page物件
這裡我們通過wxappStore.createPage
來建立。對比一下Store.js和原來的建立方法的區別
// 原來的建立方法
Page({
data: {
message: ``
},
onLoad: function () {
this.setData({
message: `hello world`
})
}
})
複製程式碼
// 增加全域性狀態管理之後
import wxappStore from "../../lib/Store.js";
Page(wxappStore.createPage({
// 第一個引數和原來傳入Page方法的option沒有區別。其中的data會作為全域性共享物件來使用。
data: {
message: ``
},
onLoad: function () {
// 通過dispatch方法,進行一個非同步操作。
this.store.dispatch({
name: `testAction`,
payload: `hello world`
});
// 通過commit方法,修改全域性狀態。
this.store.commit({
name: `testMutation`,
payload: `hello world`
});
}
},
// 第二個引數是一個物件,其中包含mutations和actions
{
mutations: {
testMutation: function({ setData, payload, data }) {
setData({
message: payload
});
}
},
actions: {
testAction: function ({ commit, payload, data }) {
setTimeout(() => {
commit({
name: `testMutation`,
payload: payload
});
});
}
}
}))
複製程式碼
wxappStore.createPage
方法有兩個引數。
第一個引數和原來傳入Page方法的option沒有區別。其中的data會作為全域性共享物件來使用。
第二個引數是一個物件,其中包含mutations
和actions
2.3 使用mutation
mutation和Vuex中的mutation類似,它通過同步的方式修改狀態。可以通過commit呼叫。
2.3.1 定義mutation
mutations在wxappStore.createPage
的第二個引數中定義,它用於修改全域性狀態。mutation通常同步的。mutation方法的引數是一個物件,包含三個屬性:
- setData
function
: 用來修改全域性狀態,在微信小程式中直接修改狀態不會觸發頁面重匯。 - payload
object
:修改的狀態,可以是一個物件,也可以是String等基礎資料型別 - data
object
:當前狀態
mutations: {
testMutation: function({ setData, payload, data }) {
setData({
message: payload
});
}
},
複製程式碼
2.3.2 呼叫mutation
通過commit方法呼叫mutation,它的引數是一個物件,包含兩個屬性:
- name
String
:mutation的名稱 - payload
Object
:需要修改的狀態,和Vuex的payload類似。
this.store.commit({
name: `testMutation`,
payload: `hello world`
});
複製程式碼
2.4 使用action
action和Vuex中action概念類似,通常包含非同步操作,在非同步操作完成後進行commit操作。
2.4.1 定義action
action方法的引數是一個引數,包含3個屬性:
- commit
function
:執行commit操作 - payload
Object
:資料物件,和Vuex型別 - data
Object
:當前狀態
actions: {
testAction: function ({ commit, payload, data }) {
setTimeout(() => {
commit({
name: `testMutation`,
payload: payload
});
});
}
}
複製程式碼
2.4.2 呼叫action
通過dispatch方法呼叫action,它的引數是一個物件,包含兩個屬性:
- name
String
:action的名稱 - payload
Object
:需要修改的狀態,和Vuex的payload類似。
this.store.dispatch({
name: `testAction`,
payload: `hello world`
});
複製程式碼
2.5 建立Component
在Component中我們需要完成兩項工作
第一將全域性狀態繫結到當前元件的data屬性上,並將元件的data屬性繫結到頁面元素上。
第二元件需要使用commit或者dispatch完成全域性狀態的修改。
這裡Store.j通過wxappStore.createComp
來建立Component,它會通過代理的方式為Component實現全域性狀態管理的功能。
import wxappStore from "../lib/Store.js";
Component(wxappStore.createComp({
data: {
localtimeData: ``
},
ready: function () {
// 繫結全域性狀態
this.getGlobalData({ globalDataKey: `localtime`, localDataKey: `localtimeData` });
// 改變全域性狀態
this.store.commit({
name: `testMutation`,
payload: (new Date()).toLocaleTimeString()
})
}
}))
複製程式碼
<view>讀取全域性狀態:{{localtimeData}}</view>
複製程式碼
2.5.1 全域性狀態繫結
全域性狀態繫結通過getGlobalData
這個例項方法實現,這個方法並不在小程式的執行環境中,它是Store.js執行的過程中插入到Component例項中的。
getGlobalData
不能再created
回撥中呼叫,應為component的例項方法setData
不能再created
中呼叫。
getGlobalData
的引數是一個物件,包含兩個屬性:
- globalDataKey
String
:這個屬性表示需要全域性狀態的屬性名,這個全域性狀態將於component的本地狀態繫結。 - localDataKey
String
:這個屬性表示本地狀態的屬性名,這個本地狀態將於全域性狀態繫結。
// 繫結全域性狀態
this.getGlobalData({ globalDataKey: `localtime`, localDataKey: `localtimeData` });
複製程式碼
2.5.2 改變全域性狀態
可以使用store.commit
或者store.dispatch
,store
並不是小程式的執行環境中內建的,同樣是通過Store.js插入到每一個component例項中。它的使用方法和Page中的類似。
3. 這套框架的不足
-
Store.js借用了Page物件的data屬性來完成全域性狀態管理,所以data屬性的職責並不單一。data屬性兼具了頁面ViewModel的功能和全域性狀態的功能。但是Page中的data屬性本來也具有全域性意義,所以兩者的衝突並不大。
-
component中的data屬性職責並不單一。它兼具了本地屬性的功能和繫結全域性狀態的功能。而且直接通過setData修改component中的data並不能觸發全域性狀態的改變,因為data的作用域僅限於當前component,必須通過
store.commit
或者store.dispatch
觸發發全域性狀態的改變。 -
如果你發現其他問題,歡迎留言,我們共同進步!