|
選用Taro做技(ji)術框(kuang)架的(de)(de)原因(yin):最近(jin)公司需要開(kai)(kai)(kai)發一款新(xin)的(de)(de)小(xiao)程(cheng)序(xu),主要是做付(fu)(fu)費知識相(xiang)關的(de)(de)產(chan)品,涉(she)及(ji)到了(le)虛擬商品支付(fu)(fu),對于IOS的(de)(de)對于虛擬商品支付(fu)(fu)的(de)(de)種種限制(zhi),加上類似小(xiao)程(cheng)序(xu)的(de)(de)相(xiang)關調(diao)研,決定IOS支付(fu)(fu)的(de)(de)方式走(zou)h5公總號支付(fu)(fu)繞開(kai)(kai)(kai)限制(zhi),所以在(zai)框(kuang)架選型(xing)上面需要一套代碼(ma)(ma)加一點(dian)兼容代碼(ma)(ma),就可以生成小(xiao)程(cheng)序(xu)和H5版本(ben)的(de)(de)庫(ku),考(kao)慮到本(ben)身技(ji)術棧以react為主,所以最后老大選擇了(le)Taro進行開(kai)(kai)(kai)發 對于Taro的簡(jian)單介(jie)紹以及提供能力(li)可(ke)以瀏覽(lan) Taro初探 需求場景在微(wei)信小程序里面(mian),需(xu)(xu)要(yao)做助力、拼團等邏(luo)輯的時候(hou),有(you)些需(xu)(xu)要(yao)鑒權的接口等,要(yao)再(zai)用戶授權登錄完畢之后(hou),在請求的 header 帶(dai)上用戶的 accessToken ,所以要(yao)確保這(zhe)些接口在用戶登錄完成之后(hou)再(zai)開始進行請求 之所以要用(yong)戶授權登(deng)錄而不用(yong)小程序的靜態登(deng)錄方式(shi)(shi),是(shi)因為(wei)在兼容H5的時候,登(deng)陸流(liu)程是(shi)通(tong)過公眾號(hao)登(deng)錄的,在不想產生多余的數據下,使用(yong)用(yong)戶的 union_id 作為(wei)唯一依(yi)據,用(yong) wx.login這種形式(shi)(shi)拿用(yong)戶的 code 登(deng)錄只能拿到 open_id ,與我們的需求不符合 UnionID機(ji)制說(shuo)明 · 小程序 我們這(zhe)邊與(yu)后端約(yue)定(ding)是先通過(guo)用(yong)(yong)戶授權 wx.getUserInfo ,拿(na)到(dao)用(yong)(yong)戶信息(xi)發送給后端進行注冊或者登陸,后端返(fan)回一個 accessToken 作為用(yong)(yong)戶的(de)(de)憑證,調用(yong)(yong)其(qi)他接口(kou)的(de)(de)時候在 header 帶著這(zhe)個 accessToken ,后端就(jiu)能(neng)在需要(yao)的(de)(de)時候根據(ju) accessToken 獲取到(dao)當前用(yong)(yong)戶信息(xi) 小程序的登錄流程如下
由于小程序(xu)的(de)生(sheng)命周期機制,生(sheng)命周期是(shi)異步執行(xing)的(de),生(sheng)命周期之間是(shi)無法阻(zu)塞執行(xing),如果在 onLaunch 的(de)時候進行(xing)用戶登錄的(de)邏(luo)輯,在弱網(wang)的(de)情況(kuang)下,會出現一種(zhong)情況(kuang)就是(shi)用戶登錄沒完成的(de)情況(kuang)下,還沒拿到 accessToken 就開始了(le)page里面(mian)的(de)請求接口,這樣會導致(zhi)接口報(bao)錯 解決思路利用修飾(shi)器 Decorator 、React的(de)(de)高(gao)階組(zu)件 HOC 以及 async/await ,劫持當前頁面調(diao)用接口的(de)(de)聲明(ming)周期,等待(dai)封裝好的(de)(de)用戶登錄(lu)邏輯(ji)執行(xing)完(wan)以后,再進行(xing)當前聲明(ming)周期里面其他(ta)調(diao)用的(de)(de)執行(xing)。 舉個例子在分享助力的(de)場景下,新用戶(hu)點(dian)擊分享用戶(hu)的(de)卡片進來小程序(xu),需要彈(dan)(dan)出一(yi)個授(shou)權彈(dan)(dan)框等用戶(hu)授(shou)權登陸成功以后,才能(neng)進行助力接(jie)口的(de)調用。 要注意的是,劫持的是當前聲明周(zhou)期(qi)的方法,并不會(hui)阻塞到其他(ta)生命(ming)周(zhou)期(qi),例如劫持 willMount 的時候, didShow 、 didMount 等周(zhou)期(qi)依(yi)然會(hui)照樣按順序(xu)執行(xing)(xing),并不會(hui)等待 willMount 結(jie)束后再進(jin)行(xing)(xing) 代碼分享主(zhu)要分享修飾器的(de)使用以及作用,登陸邏(luo)輯主(zhu)要參考流程圖即可,代碼暫不(bu)做分享 寫一個能劫持傳入組件生命周期的修飾器由于Taro暫時(shi)不支持(chi)無狀態組(zu)件,所(suo)以只能使(shi)用HOC的(de)(de)反向(xiang)劫持(chi)能力,繼承(cheng)傳入的(de)(de)組(zu)件,這(zhe)個時(shi)候就可(ke)以通(tong)過等待(dai)登錄邏輯完成,再執行劫持(chi)的(de)(de)生命周期(qi) withLogin.js
const LIFE_CYCLE_MAP = ['willMount', 'didMount', 'didShow'];
/**
*
* 登錄鑒權
*
* @param {string} [lifecycle] 需要等待的鑒權完再執行的生命周期 willMount didMount didShow
* @returns 包裝后的Component
*
*/
function withLogin(lifecycle = 'willMount') {
// 異常規避提醒
if (LIFE_CYCLE_MAP.indexOf(lifecycle) < 0) {
console.warn(
`傳入的生命周期不存在, 鑒權判斷異常 ===========> $_{lifecycle}`
);
return Component => Component;
}
return function withLoginComponent(Component) {
// 避免H5兼容異常
if (tool.isH5()) {
return Component;
}
// 這里還可以通過redux來獲取本地用戶信息,在用戶一次登錄之后,其他需要鑒權的頁面可以用判斷跳過流程
// @connect(({ user }) => ({
// userInfo: user.userInfo,
// }))
class WithLogin extends Component {
constructor(props) {
super(props);
}
async componentWillMount() {
if (super.componentWillMount) {
if (lifecycle === LIFE_CYCLE_MAP[0]) {
const res = await this.$_autoLogin();
if (!res) return;
}
super.componentWillMount();
}
}
async componentDidMount() {
if (super.componentDidMount) {
if (lifecycle === LIFE_CYCLE_MAP[1]) {
const res = await this.$_autoLogin();
if (!res) return;
}
super.componentDidMount();
}
}
async componentDidShow() {
if (super.componentDidShow) {
if (lifecycle === LIFE_CYCLE_MAP[2]) {
const res = await this.$_autoLogin();
if (!res) return;
}
super.componentDidShow();
}
}
}
$_autoLogin = () => {
// ...這里是登錄邏輯
}
}
}
export default withLogin;
復制代碼
注意使用的組件內必須有對應定(ding)義的生命周期,而且 不能使用箭(jian)頭(tou)函(han)數式(shi) ,例(li)如(ru) componentWillMount(){} 不能寫成 componentWillMount = () => {} ,會劫(jie)持失敗 需要登錄鑒權頁面的使用方式pages/xxx/xxx.js
import Taro, { Component } from '@tarojs/taro';
import { View } from '@tarojs/components';
import withLogin from './withLogin'
@withLogin()
class Index extends Component {
componentWillMount(){
console.log('Index willMount')
// 需要帶accessToken調用的接口等
}
componentDidMount(){
console.log('Index didMount')
}
render() {
console.log('Index render');
return <View />;
}
}
export default Index;
復制代碼
注意
利(li)用修(xiu)飾器(qi)這個特性,我們還可以(yi)對小(xiao)程序做一層瀏覽打點,分享封裝等(deng)操作 |