|
選用Taro做技術(shù)框架的原因:最近公司需要開(kāi)發(fā)一款新的小程序,主要是做付費(fèi)知識(shí)相關(guān)的產(chǎn)品,涉及到了虛擬商品支付,對(duì)于IOS的對(duì)于虛擬商品支付的種種限制,加上類似小程序的相關(guān)調(diào)研,決定IOS支付的方式走h(yuǎn)5公總號(hào)支付繞開(kāi)限制,所以在框架選型上面需要一套代碼加一點(diǎn)兼容代碼,就可以生成小程序和H5版本的庫(kù),考慮到本身技術(shù)棧以react為主,所以最后老大選擇了Taro進(jìn)行開(kāi)發(fā) 對(duì)于Taro的簡(jiǎn)單介紹以及提供能力可以瀏覽 Taro初探 需求場(chǎng)景在微信小程序里面,需要做助力、拼團(tuán)等邏輯的時(shí)候,有些需要鑒權(quán)的接口等,要再用戶授權(quán)登錄完畢之后,在請(qǐng)求的 header 帶上用戶的 accessToken ,所以要確保這些接口在用戶登錄完成之后再開(kāi)始進(jìn)行請(qǐng)求 之所以要用戶授權(quán)登錄而不用小程序的靜態(tài)登錄方式,是因?yàn)樵诩嫒軭5的時(shí)候,登陸流程是通過(guò)公眾號(hào)登錄的,在不想產(chǎn)生多余的數(shù)據(jù)下,使用用戶的 union_id 作為唯一依據(jù),用 wx.login這種形式拿用戶的 code 登錄只能拿到 open_id ,與我們的需求不符合 UnionID機(jī)制說(shuō)明 · 小程序 我們這邊與后端約定是先通過(guò)用戶授權(quán) wx.getUserInfo ,拿到用戶信息發(fā)送給后端進(jìn)行注冊(cè)或者登陸,后端返回一個(gè) accessToken 作為用戶的憑證,調(diào)用其他接口的時(shí)候在 header 帶著這個(gè) accessToken ,后端就能在需要的時(shí)候根據(jù) accessToken 獲取到當(dāng)前用戶信息 小程序的登錄流程如下
由于小程序的生命周期機(jī)制,生命周期是異步執(zhí)行的,生命周期之間是無(wú)法阻塞執(zhí)行,如果在 onLaunch 的時(shí)候進(jìn)行用戶登錄的邏輯,在弱網(wǎng)的情況下,會(huì)出現(xiàn)一種情況就是用戶登錄沒(méi)完成的情況下,還沒(méi)拿到 accessToken 就開(kāi)始了page里面的請(qǐng)求接口,這樣會(huì)導(dǎo)致接口報(bào)錯(cuò) 解決思路利用修飾器 Decorator 、React的高階組件 HOC 以及 async/await ,劫持當(dāng)前頁(yè)面調(diào)用接口的聲明周期,等待封裝好的用戶登錄邏輯執(zhí)行完以后,再進(jìn)行當(dāng)前聲明周期里面其他調(diào)用的執(zhí)行。 舉個(gè)例子在分享助力的場(chǎng)景下,新用戶點(diǎn)擊分享用戶的卡片進(jìn)來(lái)小程序,需要彈出一個(gè)授權(quán)彈框等用戶授權(quán)登陸成功以后,才能進(jìn)行助力接口的調(diào)用。 要注意的是,劫持的是當(dāng)前聲明周期的方法,并不會(huì)阻塞到其他生命周期,例如劫持 willMount 的時(shí)候, didShow 、 didMount 等周期依然會(huì)照樣按順序執(zhí)行,并不會(huì)等待 willMount 結(jié)束后再進(jìn)行 代碼分享主要分享修飾器的使用以及作用,登陸邏輯主要參考流程圖即可,代碼暫不做分享 寫一個(gè)能劫持傳入組件生命周期的修飾器由于Taro暫時(shí)不支持無(wú)狀態(tài)組件,所以只能使用HOC的反向劫持能力,繼承傳入的組件,這個(gè)時(shí)候就可以通過(guò)等待登錄邏輯完成,再執(zhí)行劫持的生命周期 withLogin.js
const LIFE_CYCLE_MAP = ['willMount', 'didMount', 'didShow'];
/**
*
* 登錄鑒權(quán)
*
* @param {string} [lifecycle] 需要等待的鑒權(quán)完再執(zhí)行的生命周期 willMount didMount didShow
* @returns 包裝后的Component
*
*/
function withLogin(lifecycle = 'willMount') {
// 異常規(guī)避提醒
if (LIFE_CYCLE_MAP.indexOf(lifecycle) < 0) {
console.warn(
`傳入的生命周期不存在, 鑒權(quán)判斷異常 ===========> $_{lifecycle}`
);
return Component => Component;
}
return function withLoginComponent(Component) {
// 避免H5兼容異常
if (tool.isH5()) {
return Component;
}
// 這里還可以通過(guò)redux來(lái)獲取本地用戶信息,在用戶一次登錄之后,其他需要鑒權(quán)的頁(yè)面可以用判斷跳過(guò)流程
// @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;
復(fù)制代碼
注意使用的組件內(nèi)必須有對(duì)應(yīng)定義的生命周期,而且 不能使用箭頭函數(shù)式 ,例如 componentWillMount(){} 不能寫成 componentWillMount = () => {} ,會(huì)劫持失敗 需要登錄鑒權(quán)頁(yè)面的使用方式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調(diào)用的接口等
}
componentDidMount(){
console.log('Index didMount')
}
render() {
console.log('Index render');
return <View />;
}
}
export default Index;
復(fù)制代碼
注意
利用修飾器這個(gè)特性,我們還可以對(duì)小程序做一層瀏覽打點(diǎn),分享封裝等操作 |