在Vue3中實(shí)現(xiàn)四種全局狀態(tài)數(shù)據(jù)的統(tǒng)一管理的方法
四種全局狀態(tài)數(shù)據(jù)
在實(shí)際開發(fā)當(dāng)中,會(huì)遇到四種全局狀態(tài)數(shù)據(jù):異步數(shù)據(jù)(一般來自服務(wù)端)
、同步數(shù)據(jù)
。同步數(shù)據(jù)又分為三種:localstorage
、cookie
、內(nèi)存
。在傳統(tǒng)的 Vue3 當(dāng)中,分別采用不同的機(jī)制來處理這些狀態(tài)數(shù)據(jù),而在 Zova 中只需要采用統(tǒng)一的Model
機(jī)制
狀態(tài)數(shù)據(jù) | 傳統(tǒng)的Vue3 | Zova |
---|---|---|
異步數(shù)據(jù) | Pinia | Model |
localstorage | Pinia + Localstorage | Model |
cookie | Pinia + Cookie | Model |
內(nèi)存 | Pinia | Model |
采用 Model 機(jī)制統(tǒng)一管理這些全局狀態(tài)數(shù)據(jù),就可以提供一些通用的系統(tǒng)能力,比如,內(nèi)存優(yōu)化
、持久化
和SSR支持
等等,從而規(guī)范數(shù)據(jù)使用方式,簡化代碼結(jié)構(gòu),提升代碼的可維護(hù)性
特性1. 支持異步數(shù)據(jù)和同步數(shù)據(jù)
Zova Model 的基座是TanStack Query。TanStack Query 提供了強(qiáng)大的數(shù)據(jù)獲取、緩存和更新能力。如果你沒有使用過類似TanStack Query的數(shù)據(jù)管理機(jī)制,那么強(qiáng)烈建議了解一下,相信你一定會(huì)受到思想的洗禮
但是,TanStack Query 的核心是對(duì)異步數(shù)據(jù)(一般來自服務(wù)端)進(jìn)行管理。Zova Model 在 TanStack Query 的基礎(chǔ)上做了擴(kuò)展,因此也支持同步數(shù)據(jù)的管理。換而言之,以下所述所有特性和能力同時(shí)適用于異步數(shù)據(jù)
和同步數(shù)據(jù)
特性2. 自動(dòng)緩存
對(duì)獲取的異步數(shù)據(jù)進(jìn)行本地緩存,避免重復(fù)獲取。對(duì)于同步數(shù)據(jù),會(huì)自動(dòng)針對(duì) localstorage 或者 cookie 進(jìn)行讀寫操作
特性3. 自動(dòng)更新
提供數(shù)據(jù)過期策略,在合適的時(shí)機(jī)自動(dòng)更新
特性4. 減少重復(fù)請(qǐng)求
在程序的多個(gè)地方同時(shí)訪問數(shù)據(jù),將只調(diào)用一次服務(wù)端 api。如果是同步數(shù)據(jù),也只針對(duì) localstorage 或者 cookie 調(diào)用一次操作
特性5. 內(nèi)存優(yōu)化
通過 Zova Model 管理的數(shù)據(jù),雖然是全局范圍的狀態(tài),但是并不總是占用內(nèi)存,而是提供了內(nèi)存釋放與回收的機(jī)制。具體而言,就是在創(chuàng)建 Vue 組件實(shí)例時(shí)根據(jù)業(yè)務(wù)的需要?jiǎng)?chuàng)建緩存數(shù)據(jù),當(dāng) Vue 組件實(shí)例卸載時(shí)釋放對(duì)緩存數(shù)據(jù)的引用,到達(dá)約定的過期時(shí)間如果仍然沒有其他 Vue 組件引用,就會(huì)觸發(fā)回收機(jī)制(GC),完成對(duì)內(nèi)存的釋放,從而節(jié)約內(nèi)存占用。這對(duì)于大型項(xiàng)目,用戶需要長時(shí)間進(jìn)行界面交互的場景,具有顯著的好處
特性6. 持久化
本地緩存可以持久化,當(dāng)頁面刷新時(shí)可以自動(dòng)恢復(fù),避免服務(wù)端調(diào)用。如果是異步數(shù)據(jù),就會(huì)自動(dòng)持久化到 IndexDB 中,從而滿足大數(shù)據(jù)量的存儲(chǔ)需要。如果是同步數(shù)據(jù),就會(huì)自動(dòng)持久化到 localstorage 或者 cookie
內(nèi)存優(yōu)化
與持久化
配合發(fā)揮作用,對(duì)于大型項(xiàng)目效果更佳明顯。比如,第一次從服務(wù)端獲取的數(shù)據(jù),會(huì)生成本地緩存,并自動(dòng)持久化。當(dāng)頁面不再使用并且過期時(shí),會(huì)自動(dòng)銷毀本地緩存,從而釋放內(nèi)存。當(dāng)再次訪問該數(shù)據(jù)時(shí),會(huì)自動(dòng)從持久化中恢復(fù)本地緩存數(shù)據(jù),而不是再次從服務(wù)端獲取數(shù)據(jù)
特性7. SSR支持
不同類型的狀態(tài)數(shù)據(jù),在 SSR 模式下也會(huì)有不同的實(shí)現(xiàn)機(jī)制。Zova Model 把這些狀態(tài)數(shù)據(jù)的差異進(jìn)行抹平,并且采用統(tǒng)一的機(jī)制進(jìn)行水合,從而讓 SSR 的實(shí)現(xiàn)更加自然、直觀,顯著降低了心智負(fù)擔(dān)
特性8. 自動(dòng)命名空間隔離
Zova 通過 Model Bean 來管理數(shù)據(jù)。而 Bean 本身有唯一的標(biāo)識(shí),可以作為數(shù)據(jù)的命名空間,從而自動(dòng)保證了 Bean 內(nèi)部狀態(tài)數(shù)據(jù)命名的唯一性,避免數(shù)據(jù)沖突
如何創(chuàng)建一個(gè)Model Bean
Zova提供了VS Code插件,通過右鍵菜單可以非常便利的創(chuàng)建一個(gè)Model Bean
右鍵菜單 - [模塊路徑]:
Zova Create/Bean: Model
依據(jù)提示輸入 model bean 的名稱,比如todo
,VSCode 插件會(huì)自動(dòng)添加 model bean 的代碼骨架
比如,在 demo-todo 模塊中創(chuàng)建一個(gè) 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
異步數(shù)據(jù)
TanStack Query 的核心是對(duì)服務(wù)端數(shù)據(jù)進(jìn)行管理。為簡化起見,這里僅展示select方法的定義與使用:
- 完整代碼示例,請(qǐng)參見:demo-todo
如何定義
@Model() export class ModelTodo { select() { return this.$useQueryExisting({ queryKey: ['select'], queryFn: async () => { return this.scope.service.todo.select(); }, }); } }
- 調(diào)用$useQueryExisting 創(chuàng)建 Query 對(duì)象
- 為何不使用
$useQuery
方法?因?yàn)楫惒綌?shù)據(jù)一般是在需要時(shí)才進(jìn)行異步加載。因此我們需要確保在多次調(diào)用select
方法時(shí)始終返回同一個(gè) Query 對(duì)象,所以必須使用$useQueryExisting
方法
- 為何不使用
- 傳入 queryKey,確保本地緩存的唯一性
- 傳入 queryFn,在合適的時(shí)機(jī)調(diào)用此函數(shù)獲取服務(wù)端數(shù)據(jù)
- service.todo.select:參見Api服務(wù)
如何使用
demo-todo/src/page/todo/controller.ts
import { ModelTodo } from '../../bean/model.todo.js'; export class ControllerPageTodo { @Use() $$modelTodo: ModelTodo; }
- 注入 Model Bean 實(shí)例:$$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> ); } }
- 調(diào)用 select 方法獲取 Query 對(duì)象
- render 方法會(huì)多次執(zhí)行,重復(fù)調(diào)用 select 方法返回的是同一個(gè) Query 對(duì)象
- 直接使用 Query 對(duì)象中的狀態(tài)和數(shù)據(jù)
如何支持SSR
在 SSR 模式下,我們需要這樣使用異步數(shù)據(jù):在服務(wù)端加載狀態(tài)數(shù)據(jù),然后通過 render 方法渲染成 html 字符串。狀態(tài)數(shù)據(jù)和 html 字符串會(huì)同時(shí)發(fā)送到客戶端,客戶端在進(jìn)行水合時(shí)仍然使用此相同的狀態(tài)數(shù)據(jù),從而保持狀態(tài)的一致性
要實(shí)現(xiàn)以上邏輯,在 Zova Model 中只需要執(zhí)行一個(gè)步驟:
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__
方法中調(diào)用suspense
等待異步數(shù)據(jù)加載完成
同步數(shù)據(jù): localstorage
由于服務(wù)端不支持window.localStorage
,因此 localstorage 狀態(tài)數(shù)據(jù)不參與 SSR 的水合過程
下面演示把用戶信息存入 localstorage,當(dāng)頁面刷新時(shí)也會(huì)保持狀態(tài)
如何定義
export class ModelUser extends BeanModelBase { user?: ServiceUserEntity; protected async __init__() { this.user = this.$useQueryLocal({ queryKey: ['user'], }); } }
- 與
異步數(shù)據(jù)
定義不同,同步數(shù)據(jù)直接在初始化方法__init__
中定義 - 調(diào)用$useQueryLocal 創(chuàng)建 Query 對(duì)象
- 傳入 queryKey,確保本地緩存的唯一性
如何使用
直接像常規(guī)變量一樣讀取和設(shè)置數(shù)據(jù)
const user = this.user; this.user = newUser;
同步數(shù)據(jù): cookie
在服務(wù)端會(huì)自動(dòng)使用Request Header
中的 Cookies,在客戶端會(huì)自動(dòng)使用document.cookie
,因此會(huì)自動(dòng)保證 SSR 水合過程中 cookie 狀態(tài)數(shù)據(jù)的一致性
下面演示把用戶 Token 存入 cookie,當(dāng)頁面刷新時(shí)也會(huì)保持狀態(tài)。這樣,在 SSR 模式下,客戶端和服務(wù)端都可以使用相同的jwt token
訪問后端 API 服務(wù)
如何定義
export class ModelUser extends BeanModelBase { token?: string; protected async __init__() { this.token = this.$useQueryCookie({ queryKey: ['token'], }); } }
- 與
異步數(shù)據(jù)
定義不同,同步數(shù)據(jù)直接在初始化方法__init__
中定義 - 調(diào)用$useQueryCookie 創(chuàng)建 Query 對(duì)象
- 傳入 queryKey,確保本地緩存的唯一性
如何使用
直接像常規(guī)變量一樣讀取和設(shè)置數(shù)據(jù)
const token = this.token; this.token = newToken;
同步數(shù)據(jù): 內(nèi)存
在 SSR 模式下,服務(wù)端定義的全局狀態(tài)數(shù)據(jù)會(huì)同步到客戶端,并自動(dòng)完成水合
下面演示基于內(nèi)存的全局狀態(tài)數(shù)據(jù)
如何定義
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'], }); } }
- 與
異步數(shù)據(jù)
定義不同,同步數(shù)據(jù)直接在初始化方法__init__
中定義 - 調(diào)用$useQueryMem 創(chuàng)建 Query 對(duì)象
- 傳入 queryKey,確保本地緩存的唯一性
如何使用
直接像常規(guī)變量一樣讀取和設(shè)置數(shù)據(jù)
const cBrand = this.cBrand; this.cBrand = newValue;
結(jié)語
Zova 是一款支持 IOC 容器的 Vue3 框架,在代碼風(fēng)格上結(jié)合了Vue/React/Angular的優(yōu)點(diǎn),同時(shí)規(guī)避他們的缺點(diǎn),讓我們的開發(fā)體驗(yàn)更加優(yōu)雅,減輕心智負(fù)擔(dān)。Zova已經(jīng)內(nèi)置了大量實(shí)用、有趣的功能特性,Model機(jī)制僅僅是其中一個(gè)
Zova框架已經(jīng)開源,歡迎關(guān)注,參與共建:https://github.com/cabloy/zova。
到此這篇關(guān)于在Vue3中實(shí)現(xiàn)四種全局狀態(tài)數(shù)據(jù)的統(tǒng)一管理的方法的文章就介紹到這了,更多相關(guān)Vue3全局狀態(tài)數(shù)據(jù)內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
- 關(guān)于vuex狀態(tài)刷新網(wǎng)頁時(shí)數(shù)據(jù)被清空問題及解決
- vue中v-for數(shù)據(jù)狀態(tài)值變了,但是視圖沒改變的解決方案
- vue實(shí)現(xiàn)tab切換的3種方式及切換保持?jǐn)?shù)據(jù)狀態(tài)
- Vue 重置data的數(shù)據(jù)為初始狀態(tài)操作
- vue 實(shí)現(xiàn)tab切換保持?jǐn)?shù)據(jù)狀態(tài)
- Vue唯一可以更改vuex實(shí)例中state數(shù)據(jù)狀態(tài)的屬性對(duì)象Mutation的講解
- Vue 頁面狀態(tài)保持頁面間數(shù)據(jù)傳輸?shù)囊环N方法(推薦)
- vue單頁應(yīng)用在頁面刷新時(shí)保留狀態(tài)數(shù)據(jù)的方法
相關(guān)文章
詳解Vue用axios發(fā)送post請(qǐng)求自動(dòng)set cookie
本篇文章主要介紹了Vue用axios發(fā)送post請(qǐng)求自動(dòng)set cookie,非常具有實(shí)用價(jià)值,需要的朋友可以參考下2017-05-05淺談vue引用靜態(tài)資源需要注意的事項(xiàng)
今天小編就為大家分享一篇淺談vue引用靜態(tài)資源需要注意的事項(xiàng),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2018-09-09vue子路由跳轉(zhuǎn)實(shí)現(xiàn)tab選項(xiàng)卡效果
這篇文章主要為大家詳細(xì)介紹了vue子路由跳轉(zhuǎn)實(shí)現(xiàn)tab選項(xiàng)卡效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2022-03-03Vue拖動(dòng)截圖功能的簡單實(shí)現(xiàn)方法
最近項(xiàng)目上要做一個(gè)車牌識(shí)別的功能,就需要做拖動(dòng)截圖功能了,因?yàn)榍岸问莢ue,所以下面這篇文章主要給大家介紹了關(guān)于Vue拖動(dòng)截圖功能的簡單實(shí)現(xiàn)方法,需要的朋友可以參考下2021-07-07vue-cli是什么及創(chuàng)建vue-cli項(xiàng)目的方法
vue-cli是 vue 官方提供的、快速生成 vue 工程化項(xiàng)目的工具,支持創(chuàng)建vue2和vue3的項(xiàng)目,本文給大家詳細(xì)講解vue-cli是什么及創(chuàng)建vue-cli項(xiàng)目的方法,感興趣的朋友跟隨小編一起看看吧2023-04-04在vue中實(shí)現(xiàn)給每個(gè)頁面頂部設(shè)置title
這篇文章主要介紹了在vue中實(shí)現(xiàn)給每個(gè)頁面頂部設(shè)置title,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-07-07vue-quill-editor插入圖片路徑太長問題解決方法
這篇文章主要介紹了vue-quill-editor插入圖片路徑太長問題解決方法,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-01-01Vue使用axios進(jìn)行g(shù)et請(qǐng)求拼接參數(shù)的2種方式詳解
axios中post請(qǐng)求都是要求攜帶參數(shù)進(jìn)行請(qǐng)求,這篇文章主要給大家介紹了關(guān)于Vue使用axios進(jìn)行g(shù)et請(qǐng)求拼接參數(shù)的2種方式,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2023-01-01