《Pinia 從入門到精通》Vue 3 官方狀態管理 -- 進階使用篇

《Pinia 從入門到精通》Vue 3 官方狀態管理 – 基礎入門篇
《Pinia 從入門到精通》Vue 3 官方狀態管理 – 進階使用篇
《Pinia 從入門到精通》Vue 3 官方狀態管理 – 插件擴展篇

目錄

    • Store 的模塊化設計
      • 4.1 多模塊結構設計
        • ? 推薦目錄結構(中大型項目)
      • 4.2 定義獨立模塊 Store
      • 4.3 在組件中組合多個 Store
      • 4.4 跨模塊調用(解耦調用)
      • 4.5 模塊化 Store 的命名約定
      • 4.6 所有 Store 統一導出(可選)
      • ? 小結
    • 類型系統集成(TypeScript 支持)
      • 5.1 Store 的類型推導基礎
      • 5.2 自定義類型(推薦)
        • ? 定義接口
        • ? 使用泛型定義 Store
      • 5.3 Setup Store(組合式寫法)中的類型支持
      • 5.4 類型提示與 IDE 自動補全效果
      • 5.5 類型約束下的好處
      • ? 小結
    • 持久化存儲與插件機制
      • 6.1 什么是 Pinia 插件?
      • 6.2 狀態持久化插件:`pinia-plugin-persistedstate`
        • ? 安裝
        • ? 注冊插件
      • 6.3 使用持久化配置
      • 6.4 自定義持久化策略
      • 6.5 多模塊下持久化組合
      • 6.6 自定義插件機制(進階)
      • 6.7 生命周期鉤子:`$subscribe` & `$onAction`
        • 1. `$subscribe` —— 監聽狀態變化
        • 2. `$onAction` —— 監聽 Action 執行
      • ? 小結
    • 最佳實踐總結與項目結構規范化設計
      • 7.1 推薦項目結構
      • 7.2 Store 命名規范
      • 7.3 狀態設計原則
      • 7.4 Store 類型系統統一
      • 7.5 持久化策略標準化
      • 7.6 自動化導出 Store
      • 7.7 組合邏輯封裝:`useXXXLogic`
      • ? 實戰應用:多頁面應用的 Store 模型設計范式
      • ? 統一 Store 模板(可直接復制)
    • ? 結語:Pinia 最佳實踐總覽圖

Store 的模塊化設計

隨著項目規模擴大,單一 Store 會迅速膨脹,導致維護困難。
我們將從實際項目結構出發,講解如何構建多模塊 Store,支持清晰組織、職責分離和可維護性。
Pinia 提供了天然模塊化的設計,每一個 Store 就是一個模塊,天生支持按需加載、組合調用。


4.1 多模塊結構設計

? 推薦目錄結構(中大型項目)
src/
├── stores/
│   ├── index.ts            # 導出所有 store(可選)
│   ├── user.ts             # 用戶模塊
│   ├── auth.ts             # 登錄認證模塊
│   ├── cart.ts             # 購物車模塊
│   └── product.ts          # 商品模塊

每個模塊都用 defineStore 定義自己的狀態、邏輯、計算屬性,保持內聚。


4.2 定義獨立模塊 Store

// stores/user.ts
import { defineStore } from 'pinia'export const useUserStore = defineStore('user', {state: () => ({name: '',email: ''}),actions: {setUser(name: string, email: string) {this.name = namethis.email = email}}
})
// stores/cart.ts
import { defineStore } from 'pinia'export const useCartStore = defineStore('cart', {state: () => ({items: [] as { id: number; name: string; qty: number }[]}),getters: {totalItems: (state) => state.items.reduce((sum, item) => sum + item.qty, 0)},actions: {addItem(item: { id: number; name: string; qty: number }) {this.items.push(item)}}
})

4.3 在組件中組合多個 Store

<script setup lang="ts">
import { useUserStore } from '@/stores/user'
import { useCartStore } from '@/stores/cart'const userStore = useUserStore()
const cartStore = useCartStore()function checkout() {console.log(`${userStore.name} 正在購買 ${cartStore.totalItems} 件商品`)
}
</script>

4.4 跨模塊調用(解耦調用)

Pinia 中不同 Store 可相互獨立調用,而無需手動注入依賴:

// stores/order.ts
import { defineStore } from 'pinia'
import { useUserStore } from './user'export const useOrderStore = defineStore('order', {actions: {submitOrder() {const userStore = useUserStore()console.log(`下單用戶:${userStore.name}`)// ...業務邏輯}}
})

注意調用其他 Store 必須在 action 中動態獲取,而不能在 Store 頂層直接引入(避免依賴環問題)。


4.5 模塊化 Store 的命名約定

內容命名規則示例
Store 函數useXxxStoreuseUserStore
文件名模塊名小寫user.ts
Store ID與函數名一致的小寫形式'user'
命名空間使用 id 區分,無需嵌套定義所有 Store 自動隔離

4.6 所有 Store 統一導出(可選)

你可以在 stores/index.ts 中統一導出,方便使用:

// stores/index.ts
export * from './user'
export * from './cart'
export * from './order'
// 使用
import { useUserStore, useCartStore } from '@/stores'

? 小結

模塊化是構建大型 Vue 應用的核心策略,Pinia 以其函數式 Store 和天然隔離的 Store ID 設計,使模塊化變得:

  • 更加清晰(每個模塊職責單一)
  • 更易維護(按需加載,互不干擾)
  • 更易測試(每個 Store 獨立可測試)

類型系統集成(TypeScript 支持)

Pinia 天生支持 TypeScript,基于其函數式 API 和明確的聲明結構,使得類型推導更加自然、精準。


5.1 Store 的類型推導基礎

最基礎的 defineStore 形式在 TS 中已經具備類型提示能力:

export const useCounterStore = defineStore('counter', {state: () => ({count: 0,name: 'Counter Module'}),getters: {doubleCount: (state) => state.count * 2},actions: {increment() {this.count++}}
})

此時使用該 Store 時會自動獲得類型提示:

const store = useCounterStore()
store.count       // number ?
store.increment() // 自動補全 ?

5.2 自定義類型(推薦)

雖然大多數場景下可自動推導,但我們仍推薦使用接口顯式定義 stategettersactions 類型以獲得更強可維護性。

? 定義接口
// types/store.d.ts
export interface CounterState {count: numbername: string
}export interface CounterGetters {doubleCount(state: CounterState): number
}export interface CounterActions {increment(): void
}
? 使用泛型定義 Store
import { defineStore, StoreDefinition } from 'pinia'
import type { CounterState, CounterActions, CounterGetters } from '@/types/store'export const useCounterStore: StoreDefinition<'counter', CounterState, CounterGetters, CounterActions> = defineStore('counter', {state: (): CounterState => ({count: 0,name: 'Counter Store'}),getters: {doubleCount: (state) => state.count * 2},actions: {increment() {this.count++}}
})

5.3 Setup Store(組合式寫法)中的類型支持

對于復雜邏輯,我們可以使用組合式寫法,即 setup 形式的 Store,TS 類型控制更靈活。

import { defineStore } from 'pinia'
import { ref, computed } from 'vue'export const useUserStore = defineStore('user', () => {const name = ref('Alice')const age = ref(25)const summary = computed(() => `${name.value}${age.value}歲)`)function setName(newName: string) {name.value = newName}return {name,age,summary,setName}
})

此種寫法中,Pinia 能自動推導返回值類型,無需額外泛型,只要你在返回時顯式寫出 ref / computed


5.4 類型提示與 IDE 自動補全效果

  • State 屬性:可識別為 ref<number> / ref<string>
  • Getter 屬性:識別為 ComputedRef
  • Action 方法:自動推導參數和返回值類型

舉個例子:

const userStore = useUserStore()
userStore.age.value     // number ?
userStore.summary.value // string ?
userStore.setName('Bob') // ?

5.5 類型約束下的好處

特性說明
自動補全所有屬性、方法可自動提示,無需手動查找
靜態校驗錯誤屬性/參數在編譯期即可發現,避免運行時異常
支持重構改名、移動屬性時 IDE 可自動跟蹤更新引用
接口復用同一份接口可復用在組件、接口、后端通訊中

? 小結

Pinia 在 TypeScript 項目中具備一流的類型體驗:

  • 推薦用接口明確 State / Action / Getter 結構
  • 可選使用組合式寫法提升靈活性與組合能力
  • 強類型推導貫穿編寫、使用、調試各個環節

持久化存儲與插件機制

本節將深入講解如何使用 Pinia 插件 實現 Store 狀態的持久化存儲,以及自定義擴展 Store 功能。
在實際項目中,我們常常需要:

  • 保持用戶登錄信息,即使刷新頁面也不丟失
  • 記住用戶的主題偏好、語言設置
  • 在多個 Tab 頁面之間共享狀態

Pinia 原生支持插件機制,非常適合用于這些擴展場景。


6.1 什么是 Pinia 插件?

插件是一個函數,在每個 Store 實例創建時執行。你可以通過插件:

  • 添加全局狀態
  • 劫持/監聽 Store 生命周期
  • 自動同步狀態到 localStorage / sessionStorage
  • 注入外部依賴(如 Axios)

6.2 狀態持久化插件:pinia-plugin-persistedstate

最常用的第三方插件是 pinia-plugin-persistedstate,可自動將狀態持久化到本地存儲。

? 安裝
npm install pinia-plugin-persistedstate
? 注冊插件
// main.ts
import { createPinia } from 'pinia'
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'const pinia = createPinia()
pinia.use(piniaPluginPersistedstate)app.use(pinia)

6.3 使用持久化配置

只需在 defineStore 中增加 persist 配置:

// stores/user.ts
export const useUserStore = defineStore('user', {state: () => ({token: '',theme: 'light'}),persist: true // 默認使用 localStorage
})

刷新后依然保留 token 和主題偏好。


6.4 自定義持久化策略

persist: {enabled: true,strategies: [{key: 'user-token',storage: sessionStorage,paths: ['token'] // 只存 token}]
}
  • key:本地存儲的鍵名
  • storage:可選 localStoragesessionStorage
  • paths:只持久化指定字段

6.5 多模塊下持久化組合

每個模塊 Store 都可獨立配置 persist,互不影響:

// user.ts => 存 token 到 sessionStorage
persist: {storage: sessionStorage,paths: ['token']
}// settings.ts => 存 theme 到 localStorage
persist: {storage: localStorage,paths: ['theme']
}

6.6 自定義插件機制(進階)

你可以自定義自己的插件來擴展 Store 功能:

// plugins/logger.ts
import type { PiniaPluginContext } from 'pinia'export function loggerPlugin({ store }: PiniaPluginContext) {store.$subscribe((mutation, state) => {console.log(`[${mutation.storeId}]`, mutation.type, mutation.events)})
}

注冊插件:

pinia.use(loggerPlugin)

這樣每次狀態改變都會打印日志。


6.7 生命周期鉤子:$subscribe & $onAction

Pinia 提供兩種原生生命周期鉤子:

1. $subscribe —— 監聽狀態變化
const userStore = useUserStore()userStore.$subscribe((mutation, state) => {console.log('狀態發生變化:', mutation, state)
})
2. $onAction —— 監聽 Action 執行
userStore.$onAction(({ name, args, after, onError }) => {console.log(`Action 被調用: ${name}`, args)after(() => console.log(`${name} 執行成功`))onError((err) => console.error(`${name} 報錯`, err))
})

非常適合做埋點、錯誤日志等邏輯。


? 小結

Pinia 插件機制極為強大和靈活:

功能類型工具用途描述
本地持久化pinia-plugin-persistedstate自動同步狀態到 Storage
狀態監聽$subscribe跟蹤 State 的變化
行為監聽$onAction跟蹤 Action 的執行情況
自定義擴展插件函數注入工具、處理副作用、封裝邏輯等

最佳實踐總結與項目結構規范化設計

將基于前面內容,系統梳理一套企業級 Pinia 狀態管理的最佳實踐,從模塊設計、命名規范、狀態解耦、持久化、類型安全等多個維度,構建一個清晰、穩定、可維護、易擴展的 Store 架構體系。


7.1 推薦項目結構

src/
├── stores/                # 所有 Pinia Store 模塊
│   ├── user.ts            # 用戶相關狀態
│   ├── auth.ts            # 權限與登錄認證
│   ├── ui.ts              # UI 狀態(如 sidebar)
│   ├── settings.ts        # 全局設置項
│   └── index.ts           # 自動導出所有 Store
├── types/                # Store 類型定義
│   └── store.d.ts
├── plugins/              # 自定義插件(如 router 注入、日志等)
├── composables/          # 組合邏輯封裝,可配合 Store 使用

7.2 Store 命名規范

類型命名建議示例
Store 名稱useXxxStoreuseUserStore
ID(storeId)模塊名小寫user, auth, ui
文件名模塊名小寫user.ts, auth.ts

命名統一,利于團隊協作和自動化生成。


7.3 狀態設計原則

  1. 一個模塊職責單一,避免巨型 Store
  2. 狀態最小化:只存 UI 需要的狀態,不要存派生數據(放 getters)
  3. 與組件無關的數據放 Store,臨時數據放組件
  4. 使用 ref, computed, watch 配合使用 Store 提高響應性控制

7.4 Store 類型系統統一

統一定義 Store 的 state, getters, actions 類型接口:

// types/store.d.ts
export interface UserState { name: string; age: number }
export interface UserActions { login(): void; logout(): void }
export interface UserGetters { isAdult: boolean }

結合 StoreDefinition

export const useUserStore: StoreDefinition<'user', UserState, UserGetters, UserActions> =defineStore('user', {state: (): UserState => ({ ... }),...})

優點:

  • 強類型保障
  • 便于重構
  • 編輯器智能提示清晰

7.5 持久化策略標準化

  • token、用戶信息 → 存到 sessionStorage(瀏覽器關閉清空)
  • 用戶偏好、主題設置 → 存到 localStorage(長期保存)
  • 配置統一封裝成策略常量:
const localPersist = {storage: localStorage,paths: ['theme', 'language']
}

7.6 自動化導出 Store

// stores/index.ts
export * from './user'
export * from './auth'
export * from './settings'

支持模塊自動導入:

import { useUserStore, useAuthStore } from '@/stores'

7.7 組合邏輯封裝:useXXXLogic

業務邏輯不要堆在組件里,應該封裝成組合邏輯:

// composables/useLogin.ts
export function useLogin() {const userStore = useUserStore()const doLogin = async (formData) => {await userStore.login(formData)router.push('/dashboard')}return { doLogin }
}
  • 提高復用性
  • 分離 UI 與業務邏輯
  • 組件更輕盈可測試

? 實戰應用:多頁面應用的 Store 模型設計范式

模塊名稱典型狀態字段持久化常駐內存是否解耦 UI
usertoken, info???
uisidebar, theme???
authroles, routes???
searchkeyword, filters???(頁面級)

? 統一 Store 模板(可直接復制)

// stores/xxx.ts
import { defineStore } from 'pinia'
import type { XxxState } from '@/types/store'export const useXxxStore = defineStore('xxx', {state: (): XxxState => ({ ... }),getters: {...},actions: {...},persist: {enabled: true,strategies: [...]}
})

? 結語:Pinia 最佳實踐總覽圖

+-------------------------------+
|  模塊劃分清晰                |
|  ↓                           |
|  單一職責                    |
|  ↓                           |
|  類型定義接口統一            |
|  ↓                           |
|  Plugin 封裝 & 邏輯抽離       |
|  ↓                           |
|  狀態最小化 & 可持久化        |
|  ↓                           |
|  與 Router / API / UI 解耦    |
+-------------------------------+

Pinia 的設計理念是簡單、透明、類型友好。配合組合式 API,它不僅可以替代 Vuex,還能幫助我們構建更現代、更可控、更高效的前端架構。


本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/78049.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/78049.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/78049.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

西甲001:奧薩蘇納VS塞維利亞

西甲001&#xff1a;奧薩蘇納VS塞維利亞 奧薩蘇納主場強勢力擒塞維利亞 奧薩蘇納中場核心蒙卡約納上輪聯賽早段傷退&#xff0c;本輪將由巴勃羅-伊瓦涅斯頂替首發。當家射手布迪米爾狀態爆棚&#xff0c;近兩輪斬獲3球&#xff0c;本賽季聯賽已轟入18球創生涯新高&#xff0c;將…

C語言編程--15.四數之和

題目&#xff1a; 給你一個由 n 個整數組成的數組 nums &#xff0c;和一個目標值 target 。請你找出并返回滿足下述全部條件且不重復的四元組 [nums[a], nums[b], nums[c], nums[d]] &#xff08;若兩個四元組元素一一對應&#xff0c;則認為兩個四元組重復&#xff09;&…

2025.04.23【探索工具】| STEMNET:高效數據排序與可視化的新利器

文章目錄 1. STEMNET工具簡介2. STEMNET的安裝方法3. STEMNET常用命令 1. STEMNET工具簡介 在生物信息學領域&#xff0c;分析和處理大規模數據集是研究者們面臨的日常挑戰。STEMNET工具應運而生&#xff0c;旨在提供一個強大的平臺&#xff0c;用于探索和分析單細胞RNA測序&a…

Day-3 應急響應實戰

應急響應實戰一&#xff1a;Web入侵與數據泄露分析 1. Web入侵核心原理 ??漏洞利用路徑?? 未授權訪問&#xff1a;弱口令&#xff08;如空密碼/默認口令&#xff09;、目錄遍歷漏洞代碼注入攻擊&#xff1a;JSP/ASP木馬、PHP一句話木馬&#xff08;利用eval($_POST[cmd])&…

兩段文本比對,高亮出差異部分

用法一:computed <div class"card" v-if"showFlag"><div class"info">*紅色背景為已刪除內容&#xff0c;綠色背景為新增內容</div><el-form-item label"與上季度比對&#xff1a;"><div class"comp…

Python中的 for 與 迭代器

文章目錄 一、for 循環的底層機制示例&#xff1a;手動模擬 for 循環 二、可迭代對象 vs 迭代器關鍵區別&#xff1a; 三、for 循環的典型應用場景1. 遍歷序列類型2. 遍歷字典3. 結合 range() 生成數字序列4. 遍歷文件內容 四、迭代器的自定義實現示例&#xff1a;生成斐波那契…

Pytest教程:為什么Pytest要用插件模式?

目錄 一、歷史背景:測試框架的局限性與Pytest的設計哲學 1.1 早期測試框架的困境 1.2 Pytest的模塊化設計 二、橫向對比:插件機制如何讓Pytest脫穎而出 2.1 與Unittest/Nose的對比 2.2 插件模式的架構優勢 三、插件模式的核心優勢解析 3.1 可擴展性:從單元測試到全鏈…

【深度】如何通過MCP實現多智能體之間的協同

來源&#xff1a;騰訊技術工程、infoQ、原力注入 自 OpenAI 于 2023 年發布函數調用功能以來&#xff0c;我一直在思考如何構建一個開放的智能體與工具使用生態系統。隨著基礎模型愈發智能化&#xff0c;智能體與外部工具、數據和 API 的交互能力卻日益碎片化&#xff1a;開發…

NVIDIA自動駕駛安全與技術讀后感

ll在閱讀了 NVIDIA 自動駕駛安全報告后&#xff0c;我對該公司致力于推進自動駕駛汽車&#xff08;AV&#xff09;技術、同時優先考慮安全和標準化的承諾印象深刻。它揭示了 NVIDIA 在功能安全、法規合規性以及與全球標準組織合作方面的嚴謹態度。 ?? 報告中最引人注目的部分…

關于nginx,負載均衡是什么?它能給我們的業務帶來什么?怎么去配置它?

User 關于nginx&#xff0c;我還想知道&#xff0c;負載均衡是什么&#xff1f;它能為我的業務帶來什么&#xff1f;怎么去配置它&#xff1f; Assistant 負載均衡是 Nginx 另一個非常強大的功能&#xff0c;也是構建高可用、高性能應用的關鍵技術之一。我們來詳細了解一下。 …

前端如何優雅地對接后端

作為一名前端開發者&#xff0c;與后端對接是我們日常工作中不可避免的一部分。從API設計的理解到錯誤處理的優雅實現&#xff0c;前端需要的不只是調用接口的代碼&#xff0c;更是一種協作的藝術。本文將從Vue 3項目出發&#xff0c;分享如何與后端高效協作&#xff0c;減少聯…

PYTHON用幾何布朗運動模型和蒙特卡羅MONTE CARLO隨機過程模擬股票價格可視化分析耐克NKE股價時間序列數據

原文鏈接&#xff1a;http://tecdat.cn/?p27099 金融資產/證券已使用多種技術進行建模。該項目的主要目標是使用幾何布朗運動模型和蒙特卡羅模擬來模擬股票價格。該模型基于受乘性噪聲影響的隨機&#xff08;與確定性相反&#xff09;變量&#xff08;點擊文末“閱讀原文”獲取…

頭歌之動手學人工智能-機器學習 --- PCA

目錄 第1關&#xff1a;維數災難與降維 第2關&#xff1a;PCA算法流程 任務描述 編程要求 測試說明 第3關&#xff1a;sklearn中的PCA 任務描述 編程要求 測試說明 第1關&#xff1a;維數災難與降維 第2關&#xff1a;PCA算法流程 任務描述 本關任務&#xff1a;補充…

IOMUXC_SetPinMux的0,1參數解釋

IOMUXC_SetPinMux(IOMUXC_ENET1_RX_DATA0_FLEXCAN1_TX, 0); 這里的第二個參數 0 實際上傳遞給了 inputOnfield&#xff0c;它控制的是 SION&#xff08;Software Input On&#xff09;位。 當 inputOnfield 為 0 時&#xff0c;SION 關閉&#xff0c;此時引腳的輸入/輸出方向由…

express響應設置 以及redirect,download,json.sendFdile

Express 中常用響應方法 的整理&#xff0c;包括設置響應頭、重定向、下載、發送 JSON、發送文件等&#x1f447; &#x1f4e4; 一、設置響應頭與狀態碼 設置狀態碼 res.status(404).send(Not Found);設置響應頭 res.set(Content-Type, text/plain); // 設置內容類型 res.s…

深度學習-數值穩定性和模型初始化

到目前為止&#xff0c;我們實現的每個模型都是根據某個預先制定的分布來初始化模型的參數&#xff0c;有人會認為初始化方案時理所當然的&#xff0c;忽略了如何做出這些選擇的細節&#xff0c;甚至有人可能會覺得&#xff0c;初始化方案的選擇并不是特別重要&#xff0c;實際…

SFINAE(Substitution Failure Is Not An Error)

C 中的 SFINAE&#xff08;替換失敗并非錯誤&#xff09; SFINAE&#xff08;Substitution Failure Is Not An Error&#xff09;是 C 模板元編程的核心機制之一&#xff0c;允許在編譯時根據類型特性選擇不同的模板實現。以下通過代碼示例和底層原理&#xff0c;逐步解析 SFI…

【Python筆記 04】輸入函數、轉義字符

一、Input 輸入函數 prompt是提示&#xff0c;會在控制臺顯示&#xff0c;用作提示函數。 name input("請輸入您的姓名&#xff1a;") print (name)提示你輸入任意信息&#xff1a; 輸入input test后回車&#xff0c;他輸出input test 二、常用的轉義字符 只講…

什么是量子計算?它能做什么?

拋一枚硬幣。要么正面朝上&#xff0c;要么反面朝上&#xff0c;對吧&#xff1f;當然&#xff0c;那是在我們看到硬幣落地的結果之后。但當硬幣還在空中旋轉時&#xff0c;它既不是正面也不是反面&#xff0c;而是正面和反面都有一定的可能性。 這個灰色地帶就是量子計算的簡…

入門 Go 語言

本專欄的 Go 語言學習參考了B站UP 軟件工藝師的視頻 本節需要&#xff1a; Go 語言環境VSCode 安裝環境 下載 Go 環境&#xff0c;并安裝下載 VSCode&#xff0c;安裝。在 VSCode 中安裝 Go 擴展&#xff1a; 接下來就可以編寫 Go 語言了 第一條 Go Go 語言是一種編譯型…