选用Taro作技术框架的缘由:最近公司须要开发一款新的小程序,主要是作付费知识相关的产品,涉及到了虚拟商品支付,对于IOS的对于虚拟商品支付的种种限制,加上相似小程序的相关调研,决定IOS支付的方式走h5公总号支付绕开限制,因此在框架选型上面须要一套代码加一点兼容代码,就能够生成小程序和H5版本的库,考虑到自己技术栈以react为主,因此最后老大选择了Taro进行开发javascript
对于Taro的简单介绍以及提供能力能够浏览 Taro初探 html
在微信小程序里面,须要作助力、拼团等逻辑的时候,有些须要鉴权的接口等,要再用户受权登陆完毕以后,在请求的header
带上用户的accessToken
,因此要确保这些接口在用户登陆完成以后再开始进行请求java
之因此要用户受权登陆而不用小程序的静态登陆方式,是由于在兼容H5的时候,登录流程是经过公众号登陆的,在不想产生多余的数据下,使用用户的union_id
做为惟一依据,用wx.login
这种形式拿用户的code
登陆只能拿到open_id
,与咱们的需求不符合react
咱们这边与后端约定是先经过用户受权wx.getUserInfo
,拿到用户信息发送给后端进行注册或者登录,后端返回一个accessToken
做为用户的凭证,调用其余接口的时候在header
带着这个accessToken
,后端就能在须要的时候根据accessToken
获取到当前用户信息github
因为小程序的生命周期机制,生命周期是异步执行的,生命周期之间是没法阻塞执行,若是在
onLaunch
的时候进行用户登陆的逻辑,在弱网的状况下,会出现一种状况就是用户登陆没完成的状况下,还没拿到accessToken
就开始了page里面的请求接口,这样会致使接口报错redux
利用修饰器Decorator
、React的高阶组件HOC
以及async/await
,劫持当前页面调用接口的声明周期,等待封装好的用户登陆逻辑执行完之后,再进行当前声明周期里面其余调用的执行。小程序
在分享助力的场景下,新用户点击分享用户的卡片进来小程序,须要弹出一个受权弹框等用户受权登录成功之后,才能进行助力接口的调用。后端
要注意的是,劫持的是当前声明周期的方法,并不会阻塞到其余生命周期,例如劫持
willMount
的时候,didShow
、didMount
等周期依然会照样按顺序执行,并不会等待willMount
结束后再进行微信小程序
主要分享修饰器的使用以及做用,登录逻辑主要参考流程图便可,代码暂不作分享
因为Taro暂时不支持无状态组件,因此只能使用HOC的反向劫持能力,继承传入的组件,这个时候就能够经过等待登陆逻辑完成,再执行劫持的生命周期
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,
// }))
return 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;
复制代码
注意
使用的组件内必须有对应定义的生命周期,并且
不能使用箭头函数式
,例如componentWillMount(){}
不能写成componentWillMount = () => {}
,会劫持失败
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; 复制代码
注意
- 若是在继承的时候使用了redux去connect了数据,使用以后已自动为组件的props附带上connect的数据,被修饰的组件不须要再connect去拿这一个数据, 否则可能会出现报错
Setting data field "xxx" to undefined is invalid
.
利用修饰器这个特性,咱们还能够对小程序作一层浏览打点,分享封装等操做
因为小程序编译的缘由,小程序上面不能劫持render
, 因此在受权登陆的时候想弹出自定义弹窗
引导用户受权的话,须要经过redux
来控制是否显示弹框以及在页面组件引入自定义弹窗
的组件