在Vue3中如何实现四种全局状态数据的统一管理?
四种全局状态数据
在实际开发当中,会遇到四种全局状态数据:异步数据(一般来自服务端)、同步数据。同步数据又分为三种:localstorage、cookie、内存。在传统的 Vue3 当中,分别采用不同的机制来处理这些状态数据,而在 Zova 中只需要采用统一的Model机制
| 状态数据 | 传统的Vue3 | Zova |
|---|---|---|
| 异步数据 | Pinia | Model |
| localstorage | Pinia + Localstorage | Model |
| cookie | Pinia + Cookie | Model |
| 内存 | Pinia | Model |
采用 Model 机制统一管理这些全局状态数据,就可以提供一些通用的系统能力,比如,内存优化、持久化和SSR支持等等,从而规范数据使用方式,简化代码结构,提升代码的可维护性
特性1. 支持异步数据和同步数据
Zova Model 的基座是TanStack Query。TanStack Query 提供了强大的数据获取、缓存和更新能力。如果你没有使用过类似TanStack Query的数据管理机制,那么强烈建议了解一下,相信你一定会受到思想的洗礼
但是,TanStack Query 的核心是对异步数据(一般来自服务端)进行管理。Zova Model 在 TanStack Query 的基础上做了扩展,因此也支持同步数据的管理。换而言之,以下所述所有特性和能力同时适用于异步数据和同步数据
特性2. 自动缓存
对获取的异步数据进行本地缓存,避免重复获取。对于同步数据,会自动针对 localstorage 或者 cookie 进行读写操作
特性3. 自动更新
提供数据过期策略,在合适的时机自动更新
特性4. 减少重复请求
在程序的多个地方同时访问数据,将只调用一次服务端 api。如果是同步数据,也只针对 localstorage 或者 cookie 调用一次操作
特性5. 内存优化
通过 Zova Model 管理的数据,虽然是全局范围的状态,但是并不总是占用内存,而是提供了内存释放与回收的机制。具体而言,就是在创建 Vue 组件实例时根据业务的需要创建缓存数据,当 Vue 组件实例卸载时释放对缓存数据的引用,到达约定的过期时间如果仍然没有其他 Vue 组件引用,就会触发回收机制(GC),完成对内存的释放,从而节约内存占用。这对于大型项目,用户需要长时间进行界面交互的场景,具有显著的好处
特性6. 持久化
本地缓存可以持久化,当页面刷新时可以自动恢复,避免服务端调用。如果是异步数据,就会自动持久化到 IndexDB 中,从而满足大数据量的存储需要。如果是同步数据,就会自动持久化到 localstorage 或者 cookie
内存优化与持久化配合发挥作用,对于大型项目效果更佳明显。比如,第一次从服务端获取的数据,会生成本地缓存,并自动持久化。当页面不再使用并且过期时,会自动销毁本地缓存,从而释放内存。当再次访问该数据时,会自动从持久化中恢复本地缓存数据,而不是再次从服务端获取数据
特性7. SSR支持
不同类型的状态数据,在 SSR 模式下也会有不同的实现机制。Zova Model 把这些状态数据的差异进行抹平,并且采用统一的机制进行水合,从而让 SSR 的实现更加自然、直观,显著降低了心智负担
特性8. 自动命名空间隔离
Zova 通过 Model Bean 来管理数据。而 Bean 本身有唯一的标识,可以作为数据的命名空间,从而自动保证了 Bean 内部状态数据命名的唯一性,避免数据冲突
- 参见:Bean标识
如何创建一个Model Bean
Zova提供了VS Code插件,通过右键菜单可以非常便利的创建一个Model Bean
右键菜单 - [模块路径]:
Zova Create/Bean: Model
依据提示输入 model bean 的名称,比如todo,VSCode 插件会自动添加 model bean 的代码骨架
比如,在 demo-todo 模块中创建一个 Model Bean todo
demo-todo/src/bean/model.todo.ts
import { Model } from 'zova';
import { BeanModelBase } from 'zova-module-a-model';
@Model()
export class ModelTodo extends BeanModelBase {}
- 使用@Model 装饰器
- 继承自基类 BeanModelBase
异步数据
TanStack Query 的核心是对服务端数据进行管理。为简化起见,这里仅展示select方法的定义与使用:
- 完整代码示例,请参见:demo-todo
如何定义
@Model()
export class ModelTodo {
select() {
return this.$useQueryExisting({
queryKey: ['select'],
queryFn: async () => {
return this.scope.service.todo.select();
},
});
}
}
- 调用$useQueryExisting 创建 Query 对象
- 为何不使用
$useQuery方法?因为异步数据一般是在需要时才进行异步加载。因此我们需要确保在多次调用select方法时始终返回同一个 Query 对象,所以必须使用$useQueryExisting方法
- 为何不使用
- 传入 queryKey,确保本地缓存的唯一性
- 传入 queryFn,在合适的时机调用此函数获取服务端数据
- service.todo.select:参见Api服务
如何使用
demo-todo/src/page/todo/controller.ts
import { ModelTodo } from '../../bean/model.todo.js';
export class ControllerPageTodo {
@Use()
$$modelTodo: ModelTodo;
}
- 注入 Model Bean 实例:$$modelTodo
demo-todo/src/page/todo/render.tsx
export class RenderTodo {
render() {
const todos = this.$$modelTodo.select();
return (
<div>
<div>isLoading: {todos.isLoading}</div>
<div>
{todos.data?.map(item => {
return <div>{item.title}</div>;
})}
</div>
</div>
);
}
}
- 调用 select 方法获取 Query 对象
- render 方法会多次执行,重复调用 select 方法返回的是同一个 Query 对象
- 直接使用 Query 对象中的状态和数据
如何支持SSR
在 SSR 模式下,我们需要这样使用异步数据:在服务端加载状态数据,然后通过 render 方法渲染成 html 字符串。状态数据和 html 字符串会同时发送到客户端,客户端在进行水合时仍然使用此相同的状态数据,从而保持状态的一致性
要实现以上逻辑,在 Zova Model 中只需要执行一个步骤:
demo-todo/src/page/todo/controller.ts
import { ModelTodo } from '../../bean/model.todo.js';
export class ControllerPageTodo {
@Use()
$$modelTodo: ModelTodo;
protected async __init__() {
const queryTodos = this.$$modelTodo.select();
await queryTodos.suspense();
if (queryTodos.error) throw queryTodos.error;
}
}
- 只需要在
__init__方法中调用suspense等待异步数据加载完成
同步数据: localstorage
由于服务端不支持window.localStorage,因此 localstorage 状态数据不参与 SSR 的水合过程
下面演示把用户信息存入 localstorage,当页面刷新时也会保持状态
如何定义
export class ModelUser extends BeanModelBase {
user?: ServiceUserEntity;
protected async __init__() {
this.user = this.$useQueryLocal({
queryKey: ['user'],
});
}
}
- 与
异步数据定义不同,同步数据直接在初始化方法__init__中定义 - 调用$useQueryLocal 创建 Query 对象
- 传入 queryKey,确保本地缓存的唯一性
如何使用
直接像常规变量一样读取和设置数据
const user = this.user;
this.user = newUser;
同步数据: cookie
在服务端会自动使用Request Header中的 Cookies,在客户端会自动使用document.cookie,因此会自动保证 SSR 水合过程中 cookie 状态数据的一致性
下面演示把用户 Token 存入 cookie,当页面刷新时也会保持状态。这样,在 SSR 模式下,客户端和服务端都可以使用相同的jwt token访问后端 API 服务
如何定义
export class ModelUser extends BeanModelBase {
token?: string;
protected async __init__() {
this.token = this.$useQueryCookie({
queryKey: ['token'],
});
}
}
- 与
异步数据定义不同,同步数据直接在初始化方法__init__中定义 - 调用$useQueryCookie 创建 Query 对象
- 传入 queryKey,确保本地缓存的唯一性
如何使用
直接像常规变量一样读取和设置数据
const token = this.token;
this.token = newToken;
同步数据: 内存
在 SSR 模式下,服务端定义的全局状态数据会同步到客户端,并自动完成水合
下面演示基于内存的全局状态数据
如何定义
zova-ui-quasar/src/suite-vendor/a-quasar/modules/quasar-adapter/src/bean/model.theme.ts
export class ModelTheme extends BeanModelBase {
cBrand: string;
protected async __init__() {
this.cBrand = this.$useQueryMem({
queryKey: ['cBrand'],
});
}
}
- 与
异步数据定义不同,同步数据直接在初始化方法__init__中定义 - 调用$useQueryMem 创建 Query 对象
- 传入 queryKey,确保本地缓存的唯一性
如何使用
直接像常规变量一样读取和设置数据
const cBrand = this.cBrand;
this.cBrand = newValue;
结语
Zova 是一款支持 IOC 容器的 Vue3 框架,在代码风格上结合了Vue/React/Angular的优点,同时规避他们的缺点,让我们的开发体验更加优雅,减轻心智负担。Zova已经内置了大量实用、有趣的功能特性,Model机制仅仅是其中一个
Zova框架已经开源,欢迎关注,参与共建:https://github.com/cabloy/zova。可添加我的微信,入群交流:yangjian2025
在Vue3中如何实现四种全局状态数据的统一管理?的更多相关文章
- Python实现接口测试中的常见四种Post请求数据
前情: 在日常的接口测试工作中,模拟接口请求通常有两种方法, 利用工具来模拟,比如fiddler,postman,poster,soapUI等 利用代码来模拟,使用到一些网络模块,比如HttpClie ...
- js中this的四种使用方法
0x00:js中this的四种调用模式 1,方法调用模式 2,函数调用模式 3,构造器调用模式 4,apply.call.bind调用模式 0x01:第一种:方法调用模式 (也就是用.调用的)this ...
- javascript中this的四种用法
javascript中this的四种用法 投稿:hebedich 字体:[增加 减小] 类型:转载 时间:2015-05-11我要评论 在javascript当中每一个function都是一个对象,所 ...
- iOS中常用的四种数据持久化方法简介
iOS中常用的四种数据持久化方法简介 iOS中的数据持久化方式,基本上有以下四种:属性列表.对象归档.SQLite3和Core Data 1.属性列表涉及到的主要类:NSUserDefaults,一般 ...
- Android中Activity的四种启动方式
谈到Activity的启动方式必须要说的是数据结构中的栈.栈是一种只能从一端进入存储数据的线性表,它以先进后出的原则存储数据,先进入的数据压入栈底,后进入的数据在栈顶.需要读取数据的时候就需要从顶部开 ...
- Delphi中定义了四种布尔类型:Boolean,ByteBool,WordBool和LongBool。后面三种布尔类型是为了与其他语言兼容而引入的
bool是LongBool类型. Delphi中定义了四种布尔类型:Boolean,ByteBool,WordBool和LongBool.后面三种布尔类型是为了与其他语言兼容而引入的,一般情况下建议使 ...
- css中按钮的四种状态
css中按钮有四种状态 1. 普通状态2. hover 鼠标悬停状态3. active 点击状态4. focus 取得焦点状态 .btn:focus{outline:0;} 可以去除按钮或a标签点击后 ...
- 【温故知新】——原生js中常用的四种循环方式
一.引言 本文主要是利用一个例子,讲一下原生js中常用的四种循环方式的使用与区别: 实现效果: 在网页中弹出框输入0 网页输出“欢迎下次光临” 在网页中弹出框输入1 网页输出“查询中……” 在 ...
- stl中map的四种插入方法总结
stl中map的四种插入方法总结方法一:pair例:map<int, string> mp;mp.insert(pair<int,string>(1,"aaaaa&q ...
- Spring中bean的四种注入方式
一.前言 最近在复习Spring的相关内容,这篇博客就来记录一下Spring为bean的属性注入值的四种方式.这篇博客主要讲解在xml文件中,如何为bean的属性注入值,最后也会简单提一下使用注解 ...
随机推荐
- chromedriver.exe存放位置
chromedriver.exe存放位置 如果chromedriver.exe存放位置不对的话,driver=webdriver.Chrome() 会报错! 一般需要存放在python下面的Scrip ...
- 【Vue】el-select 数据过多替代方案
一.需求问题: 一开始就考虑使用简单el-select选取数据,但是后面数据量增多, 超过一千条开始,组件会很卡不好用,第二个是接口也慢了 数据量多的话是有一个filterable做支持了,可以输入关 ...
- 强化学习baseline论文—— rainbow算法中给出实验结果的54个atari2600游戏名称列表
alien amidar assault asterix asteroids atlantis bank_heist battle_zone beam_rider berzerk bowling bo ...
- [COCI2015-2016#1] UZASTOPNI 题解
前言 题目链接:洛谷. 题意简述 一棵有根树,节点数 \(n \leq 10^5\),每个点有权值 \(v_i \leq 2000\),现在选出一些点,满足: 一个点的父亲点若未被选择则其不能被选择. ...
- 2023上海理工大学校内选拔赛A-D题
前言 不要在意标题,既然是随记,就随性点() 今天参加了2023年中国高校计算机大赛-团队程序设计天梯赛(GPLT)上海理工大学校内选拔赛(同步赛)_ACM/NOI/CSP/CCPC/ICPC算法编程 ...
- rk3568 | 瑞芯微平台GPIO引脚驱动编写
最近在玩瑞芯微平台的产品,移植了几个设备的驱动,遇到了一些问题,总结后发现大部分问题都出在了GPIO配置的问题上,写下本篇文章,用来分享一下调试的心得. 有喜欢瑞芯微的朋友,可以加我好友,拉你进群,一 ...
- Electron初体验
为什么使用electron 最近准备开发一个国产麒麟系统上的桌面程序,主要完成Linux命令的可视化,而electron作为目前最活跃的跨平台桌面应用程序的框架之一,它可以使用网页技术(如 HTML. ...
- Visual studio 2019 无法推送代码到 GitHub
博客转载:VS2022 无法推送到GitHub,也无法克隆项目_vs连不上github-CSDN博客 问题描述` 使用vs2019 git无法推送到github 解决办法` 按照大神的描述设置,非常好 ...
- JMeter手机app录制
在移动应用的性能测试中,如何准确.全面地捕捉用户操作并生成可复用的测试脚本,始终是测试工程师面临的一大挑战.而JMeter,作为一款功能强大的开源性能测试工具,不仅在Web测试中表现优异,在手机App ...
- uniCloud 云开发Dome
实现账号密码登录,注册, 信息图片上传与查看 项目地址:https://gitee.com/jielov/uni-cloud_development 先创建云服务空间 与云函数 可参考 https:/ ...