网站首页 > 技术文章 正文
基于Vue设计中大型应用时,随着应用大小以及业务流程的膨胀,数据管理也必然成为其中的重要一环。数据管理主要包括数据的存取、刷新、传递等方面,其实这也是笔者一直很疑惑的一个点,包括在做Android应用时,数据管理应该是开发过程中很重要的一部分,网上却很少关于这方面的讨论或是框架(Vuex更多是提供数据共享功能,具体数据管理思想&实现封装还需自行把控),至少我没有发现,如果你知道什么更好的方法欢迎在评论中交流。
数据分类
根据数据的作用域,大致可以分为三类:
- 全局配置数据:与用户无关,应用的全局配置,这类数据可以考虑放在localStorage或是sessionStorage中。
- 用户数据:与登录用户绑定的数据,作用于用户登录后的所有流程,例如用户的基本信息、状态等。
- 流程数据:一个业务流程中的共享数据,具体又可细分为登录前和登录后流程数据。
根据数据的分类,主要需要注意离开作用域时以及重复进入作用域时数据的变化,简单来说,切换用户或者退出登录时,2、3两种数据应该被清空或者重置。
提供全局唯一的访问点
这也是Vuex框架的约定,state数据只能通过mutation来变更,我更推荐把这种约定作为数据访问的准则,不管是使用Vuex还是localStorage、sessionStorage,都应该封层一个全局数据访问入口,这样会极大地方便数据的统一管理和追踪。试想一下,如果从RESTful接口获取的数据需要做逻辑处理再保存时会怎么样,如果没有这样的全局唯一的访问入口,数据的获取和保存散落在各个页面中,势必增加很多额外的工作量。(当然Vuex本身支持这样的约定可以不用做额外的封装)
//封装用户数据的入口
export default{
getUserInfo(){
if(this.userInfo) return this.userInfo; //统一封装的入口可以很方便的提供一些通用的逻辑处理
this.userInfo = sessionStorage.getItem("userInfo");
this.userInfo && (this.userInfo = JSON.parse(this.userInfo));
return this.userInfo;
}
}
数据的存取&刷新
对于业务流程来说,只关心数据的获取结果,成功或者失败,所以一个功能完善的数据模块应该封装好数据的拉取、缓存、刷新,伪代码逻辑如下:
DataModule.getData().then(() => { //数据获取成功,继续业务流程 }).catch(() => { //数据获取失败,失败逻辑 })
当然,数据获取方式、刷新机制可能多种多样,但还是可以抽象出通用的特性,如果从接口设计角度来看,简单地可以抽象为fetch(数据拉取)、isNeedRefresh(是否需要刷新)两个接口,不同的数据Repository自行实现这两个接口,缓存和获取可以统一处理,然后由统一的DateCenter调用,伪代码如下(这边主要是提倡数据中心的设计思想,以Java的角度来看更易理解,前端童鞋可直接跳过):
//用户数据仓库 UserInfoRepository{ fetch(){ //userInfo的拉取逻辑 } isNeedRefresh(userInfo){ //userInfo是否需要重新fetch的判断逻辑 } } //全局唯一的数据访问入口 DataCenter{ UserInfoRepository userInfoRepo; getUserInfo(){ //这边只是伪代码示例,不考虑同步异步、userInfo的缓存细节 if(userInfoRepo.isNeedRefresh(this.userInfo)){ this.userInfo = userInfoRepo.fetch(); } return this.userInfo; } } //业务流程中调用就很简单,不需要考虑数据刷新、拉取等细节 DataCenter.getUserInfo()
当然,上述只是对问题的抽象,对应到Vuex框架的实现可以简单地使用action来完成UserInfoRepository的逻辑,实现代码如下:
//Vuex实现逻辑 export default{ state:{ userInfo:null }, mutations:{ //全局唯一的数据修改点 saveUserInfo(state,userInfo){ state.userInfo = userInfo; } }, actions:{ getUserInfo(context,req){ if(context.state.userInfo && 无需更新判断逻辑){ return Promise.resolve(context.state.userInfo); }else{ //对于数据的远程拉取需要自行封装统一的请求方法 return Axios.post(req).then(resp => { context.state.commit("saveUserInfo",resp); return Promise.resolve(context.state.userInfo); }) } } } //Vue控件中使用 this.$store.dispatch("getUserInfo",req).then(resp => { //数据获取成功逻辑 }).catch(() => { //错误提示 })
至此,对于外部业务系统来说,只需要关心数据获取之后的处理即可,每次获取到的也肯定是最新的数据。
如何确保数据非空
对于正常的流程来说,Vuex已经能够比较好的解决数据的存取问题,But,用户有意或者故意刷新了一下页面,你就会发现,诶,我数据呢,打开console一看,一堆的飘红!这也是Vuex的一个硬伤,页面刷新之后保存在内存中的数据全部都会丢失。对于这个问题的解决,笔者暂时未想到很完美的方案,这里提供两种方式做参考,如果你有更好的方案欢迎留言交流。
方式一:保存到sessionStorage或是localStorage mutations:{ //全局唯一的数据修改点 saveUserInfo(state,userInfo){ state.userInfo = userInfo; sessionStorage.setItem("userInfo",JSON.stringify(userInfo)) } }, actions:{ getUserInfo(context,req){ if(!context.state.userInfo){ context.state.userInfo = sessionStorage.getItem("userInfo"); context.state.userInfo && (context.state.userInfo = JSON.parse(context.state.userInfo)); } ...同上 } } 缺点:1、变化分散到sessionStorage/localStorage中,管理难度加大 2、sessionStorage/localStorage中的数据可能存在安全隐患,不推荐敏感数据的保存(目前在各大网站也未发现sessionStorage/localStorage中会保存很多数据) 方式二:结合Vue-Router&控件生命周期来确保数据的获取 对于全局的用户数据可在全局路由钩子中获取来确保 router.beforeEach((to, from, next) => { if (如果是必需userInfo的页面) { Store.dispatch("getUserInfo") .then(() => { next(); }) .catch(() => { //跳转至错误页面 next({ name: "error" }); }); return; } next(); }); 控件中利用beforeMount来实现 beforeMount() { Store.dispatch("getUserInfo") .then(() => { //正常业务逻辑流程 }) .catch(() => { //错误逻辑处理,这部分代码可以统一放到mixins或者Vuex中 }); } 缺点:1、每个页面需要考虑清楚各个数据的必要性 2、需要设计数据获取失败的交互逻辑,跳转错误页面等(这部分设计好问题倒不大)
业务流程中的数据传递
页面间的数据传递很简单,利用Vue-Router的params、query即可,问题是传递之后页面刷新的问题,页面刷新之后params数据会丢失,但是query数据由于会拼接在url中可以保留下来,所以对于采用何种方式传递数据以及页面刷新之后的处理,都需要根据业务流程具体分析:
对于query数据,适合传递简单数据,适用于数据的id、主键等,如交易记录的id,这样就可以在页面的生命周期钩子中根据query数据查出详细数据 beforeMount() { Axios.post({recordId:this.$route.query.id}).then().catch(); } 而对于复杂业务数据的传递则需要使用params,但是页面刷新后params数据会丢失,这时可根据params是否存在判断是否跳出流程 beforeMount() { if(this.$route.params.data){ //继续业务流程 }else{ this.$router.back();//or push到流程入口页面 } } 跳出业务流程的处理方式主要有一个问题:对于嵌套流程,跳转到流程入口可能体验上不是很好。
对于流程中间的数据,个人不是很推荐保存到Vuex,除非你能确保管理好数据的生命周期,考虑到页面回退,用户重复进入流程,甚至极端情况下用户可能会手动输入网址跳转某个页面的情况,流程数据的缓存是有一定风险。当然,这不仅仅需要前端确保数据的准确性,还需要后端确保数据的校验拦截等。
数据的生命周期维护
对于Vuex中缓存的用户数据or流程数据,都需要在切换用户or退出流程时重置,提供重置数据的功能很简单,只需要在Vuex中增加clearState的mutation即可,难点是需要理清楚什么时候情况哪些数据需要重置,推荐将不同生命周期的数据封装成不同的module,然后提供不同的clear方法,在各个变更点调用即可。
clearState(state) { //这边使用了lodash重置每个key,直接对state赋值是不起重要的 lodash.mapKeys(state, (val, key) => { lodash.unset(state, key); return key; }); }
数据绑定问题
上面解决了数据的存取问题,当用到Vuex保存的数据做页面展示时可能会碰到数据还未获取成功的问题,这时console中一堆的undefine报错,甚至可能导致页面渲染失败,解决方法可采用computed的方式获取缓存数据中的字段:
<div>{{name}}</div> computed:{ name(){ return this.$store.state.userInfo && this.$store.state.userInfo.person && this.$store.state.userInfo.person.name } }
- 上一篇: Vuex 映射完全指南(vuex引入)
- 下一篇: 简单易用的Vuex,拿来直接用就行了
猜你喜欢
- 2024-09-29 Vue实战——vue+router+vuex导航守卫进行身份验证
- 2024-09-29 shopping开源项目用vue+vue-router+vuex实现电商网站基本功能
- 2024-09-29 Vuex状态管理(vuex状态管理几种状态)
- 2024-09-29 vue2视频教程系列第二十七节—vuex中getters和actions的使用
- 2024-09-29 实现vuex(实现人生价值的根本途径是)
- 2024-09-29 Vuex 学习笔记(vuex视频教学)
- 2024-09-29 Vue 3学习:4. 集成vuex(vue集成js)
- 2024-09-29 Vue组件间通信(vue组件间通信的方法)
- 2024-09-29 vue-admin-template调用action获取用户资料
- 2024-09-29 vuex的实现以及数据流向(vuex单向数据流图)
- 最近发表
- 标签列表
-
- cmd/c (57)
- c++中::是什么意思 (57)
- sqlset (59)
- ps可以打开pdf格式吗 (58)
- phprequire_once (61)
- localstorage.removeitem (74)
- routermode (59)
- vector线程安全吗 (70)
- & (66)
- java (73)
- org.redisson (64)
- log.warn (60)
- cannotinstantiatethetype (62)
- js数组插入 (83)
- resttemplateokhttp (59)
- gormwherein (64)
- linux删除一个文件夹 (65)
- mac安装java (72)
- reader.onload (61)
- outofmemoryerror是什么意思 (64)
- flask文件上传 (63)
- eacces (67)
- 查看mysql是否启动 (70)
- java是值传递还是引用传递 (58)
- 无效的列索引 (74)