1.以往處理狀態的一些方式
第一種:App上掛globalData 這種方式就是直接寫在App裡面啦,取值賦值比較方便
App.js
App({
globalData: {
name: '前端學者',
},
});
var name = getApp().globalData.name;
getApp().globalData.name = '改個名字';
複製程式碼
第二種:自己定義一個或者多個用於儲存資料的libData檔案,自己造輪子,愛折騰的就直接擼吧
例如libData.js
module.exports = {
name: '前端學者',
}
var store = require('./path/to/lib/libData.js');
var name = store.name;
store.name = '改個名字';
複製程式碼
第三種:把要使用的資料存在頁面data或者直接存在頁面上,比較分散而且不利於管理和維護,但是對於超小且需要快速實現的專案也足夠了。別笑,我們前端不怕這樣寫,O(∩_∩)O哈哈~
dataInPage.js
Page({
data: {
name: '前端學者'
},
name: '前端學者'
});
var name = this.data.name;
var name = this.name;
this.setData('name', '改個名字');
this.name = '改個名字');
複製程式碼
2.對於處理狀態資料,有時候可能還會混著使用上面的幾種方式,隨著專案複雜度提升,狀態將難以管理。
所以呢,我們需要借鑑web端現有的一些優秀成熟的方案,今天的主角就是它了,大家都可能很熟悉,歡迎Redux出場!網上各類的資料已經很詳細地介紹,不清楚的同學務必瞭解Redux,這裡只詳細說明一下怎麼在小程式裡面使用,和在React中的用法非常相似,因為核心庫mina-redux.js(原名wechat-weapp-redux)的作者就是這麼改過來的,這個輪子已經非常棒了。下面直接上程式碼了,程式碼雖然多,但具有實站參考價值,所以直接貼上來了。
不使用任何構建工具,把微信開發者工具中專案設定的鉤子全部打上,大方地使用import和export吧,現在不需要自己寫構建了
- ES6 轉 ES5
- 上傳程式碼時樣式自動補全
- 程式碼上傳時自動壓縮
- 不校驗安全域名、TLS版本以及HTTPS證照
核心還是Redux,和幾個好用的相關庫,這幾個都是從網上精簡了拿過來的,沒有用到npm等包管理工具
lib資料夾下:
先寫redux相關的type action reducer
app.redux.js (個人喜好把type action reducer寫在一個檔案)
import regeneratorRuntime from '../lib/regenerator-runtime';
import util from '../lib/util';
import api from '../lib/api';
import { minaScecne } from '../config/config';
const WX_SYSTEM_INFO = 'WX_SYSTEM_INFO';
const WX_USER_INFO = 'WX_USER_INFO';
const WX_ON_LAUNCH = 'WX_ON_LAUNCH';
const WX_GET_CODE = 'WX_GET_CODE';
const WX_API_PROMISIFY = 'WX_API_PROMISIFY';
const LOGIN_BEGIN = 'LOGIN_BEGIN';
const LOGIN_PENDING = 'LOGIN_PENDING';
const LOGIN_SUCCESS = 'LOGIN_SUCCESS';
const LOGIN_FAIL = 'LOGIN_FAIL';
export const wxApiPromisify = () => ({
type: WX_API_PROMISIFY,
data: util.initWxMethod()
})
export const wxSystemInfo = (data) => ({
type: WX_SYSTEM_INFO,
data: data
})
export const wxUserInfo = (data) => ({
type: WX_USER_INFO,
data: data
})
export const wxOnLaunch = (data = {}) => {
const { scene, query, path } = data;
Object.keys(minaScecne).map((item => {
if (scene.toString() === item) {
data.sceneText = minaScecne[item]
}
}));
return {
type: WX_ON_LAUNCH,
data: data
}
}
export const login = async dispatch => {
const wxLoginResult = await wx.async.login();
await dispatch({
type: WX_GET_CODE,
data: wxLoginResult
})
await dispatch({
type: LOGIN_BEGIN,
data: {
isFetching: false
}
})
await dispatch({
type: LOGIN_PENDING,
data: {
isFetching: true
}
})
if(wxLoginResult.code){
try {
const apiLoginResult = await api.user.login({ code: wxLoginResult.code });
await dispatch({
type: LOGIN_SUCCESS,
data: apiLoginResult
})
wx.setStorageSync('token', apiLoginResult.data.token)
} catch (error) {
await dispatch({
type: LOGIN_FAIL,
data: error
})
}
} else {
await dispatch({
type: LOGIN_FAIL,
data: wxLoginResult.errMsg
})
}
}
export const thunkExampleAction = () => (
async dispatch => {
const wxLoginResult = await wx.async.login();
await dispatch({
type: WX_GET_CODE,
data: wxLoginResult
})
await dispatch({
type: LOGIN_BEGIN,
data: {
isFetching: false
}
})
await dispatch({
type: LOGIN_PENDING,
data: {
isFetching: true
}
})
if(wxLoginResult.code){
try {
const apiLoginResult = await api.user.login({ code: wxLoginResult.code });
await dispatch({
type: LOGIN_SUCCESS,
data: apiLoginResult
})
wx.setStorageSync('token', apiLoginResult.data.token)
} catch (error) {
await dispatch({
type: LOGIN_FAIL,
data: error
})
}
} else {
await dispatch({
type: LOGIN_FAIL,
data: wxLoginResult.errMsg
})
}
}
);
const initState = {
wxApiPromisify: {
isFinish: false
},
wxSystemInfo: {},
wxUserInfo: {},
wxOnLaunch: {},
wxLogin: {
code: null,
token: null,
userId: null,
phone: null,
errMsg: null
},
userLogin: {
isFetching: false,
data: null
}
};
export const appReducer = (state = initState, action) => {
switch (action.type) {
case WX_API_PROMISIFY:
return Object.assign({}, state, { wxApiPromisify: { isFinish: action.data } });
case WX_GET_CODE:
return Object.assign({}, state, { wxLogin: action.data });
case WX_SYSTEM_INFO:
return Object.assign({}, state, { wxSystemInfo: action.data});
case WX_USER_INFO:
return Object.assign({}, state, { wxUserInfo: action.data});
case WX_ON_LAUNCH:
return Object.assign({}, state, { wxOnLaunch: action.data});
case LOGIN_BEGIN:
var userLogin = action.data;
userLogin.isFetching = false;
return Object.assign({}, state, { userLogin });
case LOGIN_PENDING:
var userLogin = action.data;
userLogin.isFetching = true;
return Object.assign({}, state, { userLogin });
case LOGIN_SUCCESS:
var userLogin = action.data;
userLogin.isFetching = false;
return Object.assign({}, state, { userLogin });
case LOGIN_FAIL:
var userLogin = action.data;
userLogin.isFetching = false;
return Object.assign({}, state, { userLogin });
default:
return state;
}
};
複製程式碼
app.js 小程式啟動入口
import regeneratorRuntime from './lib/regenerator-runtime';
import util from './lib/util';
import { createStore, applyMiddleware, combineReducers, compose } from './lib/redux';
import thunk from './lib/redux-thunk';
import { Provider } from './lib/mina-redux';
import { appReducer } from './redux/app.redux';
import { channelReducer } from './redux/channel.redux';
import { practiceReducer } from './redux/practice.redux';
import { wxOnLaunch, wxApiPromisify, wxSystemInfo, wxUserInfo, login } from './redux/app.redux';
import composeWithDevTools from './lib/remote-redux-devtool';
import logger from './lib/redux-logger/index';
export const store = createStore(combineReducers({
appReducer,
channelReducer,
practiceReducer,
}), compose(
applyMiddleware(thunk, logger),
composeWithDevTools({ hostname: '127.0.0.1', port: 8080, secure: false })
));
App(Provider(store)({
async onLaunch(option) {
store.dispatch(wxOnLaunch(option));
store.dispatch(wxApiPromisify());
store.dispatch(wxSystemInfo(wx.getSystemInfoSync()));
store.dispatch(wxUserInfo(await wx.async.getUserInfo()));
login(store.dispatch);
}
}));
複製程式碼
home.js 頁面
import regeneratorRuntime from '../../lib/regenerator-runtime';
import util from '../../lib/util';
import { connect } from '../../lib/mina-redux';
import { getChannelList } from '../../redux/channel.redux';
const pageConfig = {
data: {
userLogin: {
data: null,
},
channelList: {
data: [],
isFetching: false,
}
},
async onLoad(option) {
try {
console.log(` ${getCurrentPages().slice(-1)[0]['__route__']} onLoad`);
util.initPageOnLoad.call(this, option);
wx.showLoading({
title: '載入中...',
mask: true,
});
await util.waitfor(this.data, ['userLogin', 'data', 'token'], 0, null, 50);
await this.getChannelList();
wx.hideLoading();
} catch (error) {
console.error(` `, error);
}
}
}
const mapStateToPage = state => ({
...state.appReducer,
...state.channelReducer,
});
const mapDispatchToPage = dispatch => ({
getChannelList: async () => {
await dispatch(getChannelList());
}
});
const nextConfig = connect(mapStateToPage, mapDispatchToPage)(pageConfig);
Page(nextConfig);
複製程式碼
3.雖然程式碼很長,看起來可能很不爽,但是個人覺得已經比之前優雅多了,稍微熟悉一下就好,最後看下最終效果(^__^) 嘻嘻……
先開啟除錯,然後瀏覽器訪問http://localhost:8080即可,或者使用Redux DevTools除錯外掛
$ npm install -g remotedev-server
$ remotedev --hostname=localhost --port=8080
[Busy] Launching SocketCluster
[Active] SocketCluster started
Version: 6.8.0
Environment: dev
WebSocket engine: uws
Port: 8080
Master PID: 14961
Worker count: 1
Broker count: 1
複製程式碼
微信開發者工具 AppData pages/home/home 資料截圖
微信開發者工具 Console 日誌截圖
Redux RemoteDev 工具 state資料結構Chart圖
Redux RemoteDev 工具 action時間軸及Tree結構
Redux RemoteDev 工具 Log monitor
Redux DevTools具有很多強大的功能,如傳說中的“時光穿梭”等,可以實現很多很好玩的功能
THANKS
[教程]微信小程式整合Redux,引入豐富周邊工具