專案地址:點我,歡迎star和issue
mp-redux
一個用於小程式和輕量級H5應用的狀態管理工具, 使用方法是一個簡化版本的Redux。之所以是適用於輕量級應用,主要是因為沒有實現元件間的資料共享。因此不適合於複雜,龐大的前端應用。
是否你需要使用它?
如果你也和我有同樣的困惑,那麼你就該嘗試一下:
- 程式碼耦合嚴重,業務程式碼重複,往往改一處就會引起諸多功能也要跟著修改
- 業務邏輯都寫在檢視邏輯層,但是有苦於沒有辦法將業務程式碼剝離
- 程式碼越來越臃腫不堪
- 對老程式碼不敢碰,會影響很多業務邏輯
為什麼借鑑redux
- 用為redux是框架無關的,所以具有更好的可移植性,當然我這裡在內部還是做了一些"猥瑣"處理來相容多平臺
- 單一資料來源,讓狀態更容易被跟蹤
- 將業務邏輯與檢視層分離,讓程式碼更清晰,耦合更低
- 狀態都應該放在頁面的根容器去管理,分發到各個子元件。以便更好的控制業務邏輯
- 業務邏輯都放入model中,而model都是純函式,讓測試更加容易
如何使用?
拷貝 /mp-redux/index.js檔案到專案中引入即可。開包即用。
為什麼沒有使用npm?
懶
api使用方法
- 在系統入口我們必須初始化store
const mpState = require('./mp-redux/index.js');
const userInfo = require('./model/userinfo.js');
const logs = require('./model/logs.js');
mpState.createStore({
logs, // 這些model 就是redux的reduce,必須是純函式,並且需要返回一個純物件
userInfo // 這些model 就是redux的reduce,必須是純函式,並且需要返回一個純物件
}, 'onShow') // 第二個引數是劫持的生命週期函式,這是為了解決不同平臺的差異性問題導致的。後期會考慮優化
複製程式碼
- 建立model
// model 就是資料模型,是根據業務而來的
// model/userinfo.js
const actions = require('./../action/logs.js'); // 這裡同樣採用了redux的action機制
const initState = {
logs: []
}
module.exports = function (state = initState, action = {}) {
const newState = { ...state };
switch (action.type) {
case actions.addLogs:
const now = new Date();
newState.logs.push({
time: now.getHours() + ":" + now.getMinutes() + ":" + now.getSeconds(),
value: action.data
});
return newState;
case actions.clearLogs:
newState.logs = [];
return newState;
default:
return newState;
}
}
// action/userinfo.js
module.exports = {
addLogs: 'LOGS_ADD',
clearLogs: 'LOGS_CLEAR'
}
複製程式碼
- 在Page中使用
// 使用connect來注入需要訂閱的狀態,並且mp-redux會在頁面物件中自動注入dispatch方法
const mpState = require('./../../mp-redux/index.js');
const util = require('../../utils/util.js');
const logActions = require('./../../action/logs.js');
Page(mpState.connect((state) => {
return {
userInfo: state.userInfo.userInfo,
logs: state.logs.logs
}
},
{ // 在這裡所有的業務資料都儲存在store中,所以頁面如果只有業務資料的話,是不需要data屬性的。
clearLogs() {
this.dispatch({ // 通過dispatch方法來發出action,從而更新store中的資料
type: logActions.clearLogs
})
}
}))
複製程式碼
- 更容易被測試的業務程式碼 從上面我們將業務資料宣告到model中,而所有的業務資料更新以及業務資料更新的邏輯都在model中完成(參考/model/logs.js)。而model都是純函式,因此業務程式碼更加容易被測試。
// 不要吐槽,,,,,,我第一次寫測試用例。(-_-)
const actions = require('./../action/logs.js');
const model = require('./../model/logs.js');
test('1. init logs data', () => {
expect(model()).toEqual({
logs: []
})
})
test('2. add new log into empty logs', () => {
const newState = model(undefined, {
type: actions.addLogs,
data: "Test new log"
});
expect({
value: newState.logs[0].value,
len: newState.logs.length
}).toEqual({
value: "Test new log",
len: 1
});
})
test('3. add new log into logs', () => {
const newState = model({logs: [{time: '00:00:00', value: 'the first log'}]}, {
type: actions.addLogs,
data: "the second log"
});
expect({
log1: newState.logs[0].value,
log2: newState.logs[1].value,
len: newState.logs.length
}).toEqual({
log1: "the first log",
log2: "the second log",
len: 2
});
})
test('4. clear all logs', () => {
const newState = model({ logs: [
{ time: '00:00:00', value: 'log1' },
{ time: '00:00:00', value: 'log2' }
] }, {
type: actions.clearLogs
});
expect({
len: newState.logs.length
}).toEqual({
len: 0
});
})
複製程式碼
因為網際網路產品都是toC業務,UI基本上每天都在變化,但是業務的變化其實是很小的。我們通過將業務建模,在前端構建業務資料模型。而這些模型是可以預知的。因此也就可測試。
而對於一些網際網路產品,前端測試是一件非常繁瑣而複雜的事情。因此這個簡單的方案大大的降低了前端程式碼變動引起的風險,而增加的工作量也並不是很大。可以一定程度上降低業務程式碼的迴歸測試成本。