前言
在使用react开发一款小程序的时候发现,当用户已经登陆了,但是在使用的过程中在另一台设备登录了,当前设备登录失效了,但鉴于react没有路由守卫,无法在每次请求前判断是否还是有效登录,试过了很多方法,最后还是觉得发布订阅者模式舒服
什么是发布订阅者模式?
发布订阅者模式:订阅者(Subscriber) 把自己想订阅的事件注册(Subscribe)到调度中心(Topic),当发布者(Publish topic)到调度中心,也就是该事件触发时,由调度中心统一调度(Fire Event) 订阅者注册到调度中心的处理代码
举个🌰
当你是一个阅读者,你需要去图书管或者报刊买报,报刊负责人告诉你现在没有该报纸,此时你让报刊等这一款报纸到了通知你一声(此时你就是订阅者,报刊就是一个调度中心),当开发商把报纸打印出来了,并运到了报刊(此时开发商就是发布者),随后报刊就会通知你前来购买,三者的关系可以看下图
具体实现
const EventBus: IEvent = {
eventList: {}, //报刊--存放事件(订阅者说货到了要通知他)
on(key: string, callback: Function) { //存放事件的函数
!this.eventList[key] && (this.eventList[key] = []);
this.eventList[key].push(callback)
},
emit(key: string) {//当货到了,报刊要通知订阅者来买了
this.eventList[key]?.forEach(callback => callback());
}
}
具体代码有了但是要在项目中怎么使用呢?回到需求中,当登录是失效后,我们无法继续访问需要正常登录状态时才能访问的页面,所以在每一次访问前都将事件添加到Topic(报刊)上,并且事件就是跳转到登录页
EventBus.on("loginTimeOut", () => { navigate("/login") })
那么注册事件有了,在什么时候调度呢?当我们在登录失效的情况下访问接口是无法正常返回数据的,所以只需要在响应拦截的时候触发这个事件就可以达到鉴别是否已经登陆失效了。
// 如果已经登录失效,要跳转回login
if (err.response.data.errCode === 1002) {
Toast.show({
content: "请重新登陆",
icon: "loading",
maskClickable: false,
duration: 1000
})
EventBus.emit('loginTimeOut')
} else {
Toast.show({
content: err.response.data.message,
icon: "fail",
maskClickable: false,
})
}
最后
在这次的问题中,使用了发布订阅者模式进行解决了登录失效的问题,如果有更好的解决方案,欢迎指导