Vue3 狀態管理新選擇:Pinia 從入門到實戰

一、什么是pinia?

在 Vue3 生態中,狀態管理一直是開發者關注的核心話題。隨著 Vuex 的逐步淡出,Pinia 作為官方推薦的狀態管理庫,憑借其簡潔的 API、強大的功能和對 Vue3 特性的完美適配,成為了新時代的不二之選。今天我們就來深入探討 Pinia 的使用方法和最佳實踐。

如果用生活中的例子來解釋:

Pinia 就像一個 “共享冰箱”

想象一下,你和室友合租一套公寓,你們有一個?共享冰箱(Pinia Store)。這個冰箱的作用是:

  • 存放公共物品(狀態 State):比如牛奶、水果、飲料等。
  • 規定取用規則(Getters):比如 “只能在早餐時間喝牛奶”。
  • 處理特殊操作(Actions):比如 “牛奶喝完后要通知所有人”。

pinia官網:Pinia | The intuitive store for Vue.js

二、怎么創建一個Pinia

1. 創建項目的時候直接選擇Pinia

2. 項目中沒有Pinia時,手動下載

①安裝Pinia

npm install pinia

②在src中創建stores

③創建ts文件作為Pinia容器

④在counter.ts中加入以下代碼

import { defineStore } from 'pinia'
export const useCounterStore = defineStore('counter', () => {})

1、defineStore 是 Pinia 狀態管理庫 中的一個核心函數

2、參數說明
????????第一個參數 'counter':store 的唯一標識符(不可重復)
? ? ? ? 第二個參數 () => {}:store 的配置函數,返回 store 的狀態和方法

?⑤在main.ts中掛載Pinia

import './assets/main.css'import { createApp } from 'vue'
import { createPinia } from 'pinia'    // 引入創建Pinia方法
import App from './App.vue'const app = createApp(App)   app.use(createPinia())   // 掛載到app頁面app.mount('#app')

這樣就成功手動實現了Pinia的手動安轉和配置了。


三、定義第一個Pinia

1、第一個選項式Pinia示例

基礎語法:

import { defineStore } from 'pinia'// 定義并導出 Store
export const defineStore實例化對象名 = defineStore('狀態管理對象名稱', {// 狀態初始化,相當于datastate: () => ({屬性名1:屬性值1}),// 計算屬性(類似 Vue 組件中的 computed)getters: {},// 方法(類似 Vue 組件中的 methond)actions: {函數}
})

?基礎示例:

/stores/counter.ts

// 1、導入defineStore
import { defineStore } from 'pinia'
import {computed,ref} from "vue";export const useCounterStore = defineStore('counter', {state() {    // 相當于組件中的datareturn {title:"選項式計數管理器",count: 25   // 狀態管理變量數據}},getters: {     // 相當于組件中的computeddoubleCount: (state) => state.count * 2,   // 2倍計算屬性數據doubleCountPlusOne: (state) => state.count + 10  // 加10計算屬性數據},actions: {       // 相當于組件中的methodsincrement() {this.count++   // 創建函數每次點擊按鈕,count加1},decrement(){this.count--    // 創建函數每次點擊按鈕,count減1}}
})

/src/App.vue

<script setup lang="ts">
// 1、導入
import {useCounterStore} from "@/stores/counter.ts"
// 2、實例化
const counterStore = useCounterStore()
</script><template>
// 3、使用
<div class="app"><h2>標題{{counterStore.title}}</h2><p>當前計數:{{counterStore.count}}</p><p>雙倍計數:{{counterStore.doubleCount}}</p><p>計數+10:{{counterStore.doubleCountPlusOne}}</p><button @click="counterStore.increment()">點擊+1</button><button @click="counterStore.decrement()">點擊-1</button>
</div>
</template>

?運行結果:

2、第一個組合式Pinia實例

基礎語法:


import { defineStore } from 'pinia'
import { ref, computed, reactive } from 'vue'export const useStoreNameStore = defineStore('storeId', () => {// 1. State - 使用 ref 或 reactiveconst count = ref(0)const state = reactive({ name: 'example' })// 2. Getters - 使用 computedconst doubleCount = computed(() => count.value * 2)// 3. Actions - 普通函數function increment() {count.value++}// 4. 返回需要暴露的屬性和方法return {count,doubleCount,increment}
})

基礎示例:

/stores/users.ts

import {defineStore} from 'pinia'
import {computed, reactive, ref} from "vue";
export const useUserStore = defineStore('user', ()=>{let isLogin = ref(false);let username = ref('未知');let email = ref('未知');let displayName = ref('未知');let roles = reactive(['管理員','用戶','玩家','游客']);let nowRole = ref('未知');let theme = ref('白色');let language = ref('chinese');let message = ref(0);function updateLoginStatus(){if(isLogin.value){isLogin.value = !isLogin.value;username.value = "未知";displayName.value = "未知";nowRole.value = "未知";message.value = 0;email.value = "未知";}else{isLogin.value = !isLogin.value;username.value = "張三";displayName.value = "追風少年";let random:number = Math.floor(Math.random()*4);nowRole.value = roles[random];message.value = 10;email.value = "zhangsan@163.com";}}function updateUserProfile(){theme.value = theme.value === 'white' ? 'dark' : 'white';language.value = language.value === 'chinese' ? 'english' : 'chinese';}function resetUser(){username.value = "未知";displayName.value = "未知";nowRole.value = "未知";message.value = 0;roles.splice(0,roles.length);email.value = "未知";}return {isLogin,username,email,displayName,nowRole,theme,language,message,updateLoginStatus,updateUserProfile,resetUser}
})

?/src/App.vue

<script setup lang="ts">
import { useUserStore } from "@/stores/users.ts";
const userStore = useUserStore();
</script>
<template>
<div class="user-profile"><h1>用戶資料</h1><!-- 直接訪問 --><p>用戶名: {{ userStore.username }}</p><p>網名: {{ userStore.displayName }}</p><!-- 解構訪問 --><div><p>郵箱: {{userStore.email }}</p><p>登錄狀態: {{ userStore.isLogin ? '登錄':'未登錄'}}</p></div><!-- 復雜數據訪問 --><div><p>主題: {{ userStore.theme }}</p><p>語言: {{ userStore.language }}</p></div><!-- 數組數據 --><div><p>角色: {{ userStore.nowRole }}</p><p>未讀通知: {{ userStore.message}}</p></div><button @click="userStore.updateLoginStatus" >{{ userStore.isLogin ? '退出':'登錄'}}</button><button @click="userStore.updateUserProfile">更新資料</button><button @click="userStore.resetUser">重置用戶</button>
</div>
</template>

運行結果:?

?

五、綜合案例

/stores/counter.ts

import {reactive} from 'vue'
import { defineStore } from 'pinia'export const useCounterStore = defineStore('counter', () => {let products = reactive([{id: 1, 			    // 商品IDname: "蘋果16ProMax", // 商品名稱price: 12999,       // 商品價格category: "phone", // 商品類別num:123,     // 商品庫存數量rating: 4.8,       // 商品評分},{id: 2,name: "聯想拯救者",price: 23999,category: "laptop",   // 筆記本num: 0,rating: 3.8,},{id: 3,name: "華碩天選6pro",price: 11499,category: "laptop",   // 筆記本num: 15,rating: 4.9,},{id: 3,name: "iQoo平板7",price: 3499,category: "tablet",  // 平板電腦num: 899,rating: 3.7,},{id: 4,name: "iPad Air",price: 8599,category: "tablet",  // 平板電腦num: 899,rating: 4.1,},{id: 5,name: "小米手環7",price: 999,category: "watch",  // 手表num:45,rating: 4.61,},{id: 6,name: "蘋果手表6",price: 3888,category: "watch",  // 手表num:45,rating: 4.9,},{id: 6,name: "小米手機",price: 3999,category: "phone",num:425,nun: 442,rating: 4.7,},],)let avgrating = products.reduce((sum,crr) => sum+crr.rating,0) / products.lengthlet avgprice = products.reduce((sum,crr) => sum+crr.price,0) / products.lengthlet sumNum = products.reduce((sum,crr) => sum+crr.num,0)let stockNum = products.filter(item=>item.num <= 0).lengthlet categories = reactive(["phone", "laptop", "tablet", "watch"])return {products,categories,avgrating,avgprice,sumNum,stockNum}
})

/src/App.vue?

<script setup lang="ts">
import {useCounterStore} from './stores/counter.ts'
import {computed, ref} from 'vue'
const store = useCounterStore()
const products = store.products
const minPrice = ref(0)
const maxPrice = ref(0)
const filteredProducts = computed(() => {return products.filter(item => item.price >= minPrice.value && item.price <= maxPrice.value)
})
</script><template><div class="container"><h1>庫存管理系統</h1><h2>總產品數據</h2><table><tr><th>商品名</th><th>商品價格</th><th>商品庫存</th><th>商品評分</th></tr><tr v-for="(item) in products"><td>{{item.name}}</td><td>{{item.price}}</td><td>{{item.num}}</td><td>{{item.rating}}</td></tr></table><strong>產品數量:{{store.sumNum}}</strong><strong>缺貨商品數量:{{store.stockNum}}</strong><strong>平均價格:{{store.avgprice}}</strong><strong>平均評分:{{store.avgrating}}</strong><h2>分類統計</h2><div class="classify" v-for="item in store.categories"><strong>{{item}}</strong><table><tr><th>商品名</th><th>商品價格</th><th>商品庫存</th><th>商品評分</th></tr><template v-for="product in products" :key="product.id"><tr v-if="product.category === item"><td>{{ product.name }}</td><td>{{ product.price }}</td><td>{{ product.num }}</td><td>{{ product.rating }}</td></tr></template></table></div><h2>商品篩選</h2><div><label>價格區間:</label><input type="number" v-model="minPrice">---<input type="number" v-model="maxPrice"><table v-if="filteredProducts.length > 0"><tr><th>商品名</th><th>商品價格</th><th>商品庫存</th><th>商品評分</th></tr><tr v-for="item in filteredProducts" :key="item.id"><td>{{ item.name }}</td><td>{{ item.price }}</td><td>{{ item.num }}</td><td>{{ item.rating }}</td></tr></table><p v-else>暫無符合條件的商品。</p></div></div>
</template><style scoped>
.container{width:1000px;padding: 20px;border: #6e7681 1px solid;box-shadow: 2px 2px 4px #bdc1c6;margin: 0 auto;
}
h1{text-align: center;
}
table{margin: 0 auto;border: #6e7681 1px solid;width:1000px;border-collapse: collapse; /* 合并邊框 */margin-bottom: 30px;
}
strong{display: block;margin-top: 10px;
}
th,tr,td{border: #6e7681 1px solid;  /* 關鍵:為單元格添加邊框 */padding: 10px;              /* 添加內邊距使內容更美觀 */text-align: center;
}
</style>

運行結果:

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

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

相關文章

Unity相機控制

相機的控制無非移動和旋轉&#xff0c;每種操作各3個軸6個方向&#xff0c;一共12種方式。在某些需要快速驗證的項目或Demo里常常需要絲滑的控制相機調試效果。相機控制雖然不是什么高深的技術&#xff0c;但是要寫的好用還是很磨人的。 鎖定Z軸的旋轉 一個自由的相機可以繞 …

vue2 使用liveplayer加載視頻

vue2 使用liveplayer加載視頻 官網: https://www.liveqing.com/docs/manuals/LivePlayer.html支持WebRTC/MP4播放;支持m3u8/HLS播放;支持HTTP-FLV/WS-FLV/RTMP播放;支持直播和點播播放;支持播放器快照截圖;支持點播多清晰度播放;支持全屏或比例顯示;自動檢測IE瀏覽器兼容播放;支…

JavaScript語法樹簡介:AST/CST/詞法/語法分析/ESTree/生成工具

AST簡介 在平時的開發中&#xff0c;經常會遇到對JavaScript代碼進行檢查或改動的工具&#xff0c;例如ESLint會檢查代碼中的語法錯誤&#xff1b;Prettier會修改代碼的格式&#xff1b;打包工具會將不同文件中的代碼打包在一起等等。這些工具都對JavaScript代碼本身進行了解析…

Java函數式編程之【基本數據類型流】

一、基本數據類型與基本數據的包裝類 在Java編程語言中&#xff0c;int、long和double等基本數據類型都各有它們的包裝類型Integer、Long和Double。 基本數據類型是Java程序語言內置的數據類型&#xff0c;可直接使用。 而包裝類型則歸屬于普通的Java類&#xff0c;是對基本數據…

.NET Core部署服務器

1、以.NET Core5.0為例&#xff0c;在官網下載 下載 .NET 5.0 (Linux、macOS 和 Windows) | .NET 根據自己需求選擇x64還是x86&#xff0c;記住關鍵下載完成還需要下載 Hosting Bundel &#xff0c;否則不成功 2、部署https將ssl證書放在服務器上&#xff0c;雙擊導入&#…

YOLO---04YOLOv3

YOLOV3 論文地址&#xff1a;&#xff1a;【https://arxiv.org/pdf/1804.02767】 YOLOV3 論文中文翻譯地址&#xff1a;&#xff1a;【YOLO3論文中文版_yolo v3論文 中文版-CSDN博客】 YOLOv3 在實時性和精確性在當時都是做的比較好的&#xff0c;并在工業界得到了廣泛應用 …

Qt知識點3『自定義屬性的樣式表失敗問題』

問題1&#xff1a;自定義類中的自定義屬性&#xff0c;如何通過樣式表來賦值除了QT自帶的屬性&#xff0c;我們自定義的類中如果有自定義的靜態屬性&#xff0c;也可以支持樣式表&#xff0c;如下 &#xff1a; Q_PROPERTY(QColor myBorderColor READ getMyBorderColor WRITE s…

RDQS_c和RDQS_t的作用及區別

&#x1f501; LPDDR5 中的 RDQS_t 和 RDQS_c — 復用機制詳解 &#x1f4cc; 基本角色 引腳名 讀操作&#xff08;READ&#xff09;作用 寫操作&#xff08;WRITE&#xff09;作用&#xff08;當啟用Link ECC&#xff09; RDQS_t Read DQS True&#xff1a;與 RDQS_c…

測試分類:詳解各類測試方式與方法

前言&#xff1a;為什么要將測試進行分類呢&#xff1f;軟件測試是軟件生命周期中的?個重要環節&#xff0c;具有較高的復雜性&#xff0c;對于軟件測試&#xff0c;可以從不同的角度加以分類&#xff0c;使開發者在軟件開發過程中的不同層次、不同階段對測試工作進行更好的執…

新手docker安裝踩坑記錄

最近在學習docker&#xff0c;安裝和使用折騰了好久&#xff0c;在這里記錄一下。下載# 依賴安裝 sudo apt update sudo apt install -y \ca-certificates \curl \gnupg \lsb-release# 使用清華鏡像源&#xff08;Ubuntu 24.04 noble&#xff09; echo \"deb [arch$(dpkg …

TOGAF指南1

1.TOGAF標準簡介 TOGAF&#xff08;The Open Group Architecture Framework&#xff09;就像是一個企業架構的“操作手冊”。它幫助企業設計、搭建和維護自己的“系統地圖”&#xff0c;確保不同部門、技術、業務目標能像齒輪一樣協調運轉。 它的核心是&#xff1a; 用迭代的方…

[Linux入門] Linux 防火墻技術入門:從 iptables 到 nftables

目錄 一、防火墻基礎&#xff1a;netfilter 與 iptables 的關系 1??什么是 netfilter&#xff1f; 2??什么是 iptables&#xff1f; 二、iptables 核心&#xff1a;五鏈四表與規則體系 1??什么是 “鏈”&#xff08;Chain&#xff09;&#xff1f; 2?? 什么是 “…

函數fdopendir的用法

以下是關于 fdopendir 函數的詳細解析&#xff0c;結合其核心功能、參數說明及典型應用場景&#xff1a;&#x1f50d; ?一、函數功能與原型??核心作用?將已打開的目錄文件描述符&#xff08;fd&#xff09;轉換為目錄流指針&#xff08;DIR*&#xff09;&#xff0c;用于后…

[源力覺醒 創作者計劃]_文心4.5開源測評:國產大模型的技術突破與多維度能力解析

聲明&#xff1a;文章為本人真實測評博客&#xff0c;非廣告&#xff0c;并沒有推廣該平臺 &#xff0c;為用戶體驗文章 一起來輕松玩轉文心大模型吧&#x1f449; 文心大模型免費下載地址 一、引言&#xff1a;文心4.5開源——開啟多模態大模型新時代 2025年6月30日&#x…

微信小程序無法構建npm,可能是如下幾個原因

安裝位置的問題&#xff0c;【npm安裝在cd指定位置】小程序緩存的問題退出小程序&#xff0c;重新構建即可

從 MyBatis 到 MyBatis - Plus:@Options 注解的那些事兒

在 MyBatis 以及 MyBatis - Plus 的開發過程中&#xff0c;注解的使用是提升開發效率和實現特定功能的關鍵。今天我們就來聊聊 Options 注解&#xff0c;以及在 MyBatis - Plus 中它的使用場景和替代方案。 一、MyBatis 中的 Options 注解 在 MyBatis 框架中&#xff0c;Option…

轉換圖(State Transition Diagram)和時序圖(Sequence Diagram)畫圖流程圖工具

針對程序員繪制狀態轉換圖&#xff08;State Transition Diagram&#xff09;和時序圖&#xff08;Sequence Diagram&#xff09;的需求&#xff0c;以下是一些好用的工具推薦&#xff0c;涵蓋在線工具、桌面軟件和基于文本的工具&#xff0c;適合不同場景和偏好。這些工具在易…

基于php的在線酒店管理系統(源代碼+文檔+PPT+調試+講解)

課題摘要在旅游住宿行業數字化轉型的背景下&#xff0c;傳統酒店管理存在房態更新滯后、預訂渠道分散等問題。基于 PHP 的在線酒店管理系統&#xff0c;憑借其開發高效、兼容性強的特點&#xff0c;構建集客房管理、預訂處理、客戶服務于一體的綜合性管理平臺。 系統核心功能包…

視頻質量檢測中卡頓識別準確率↑32%:陌訊多模態評估框架實戰解析

原創聲明本文為原創技術解析&#xff0c;核心技術參數與架構設計引用自《陌訊技術白皮書》&#xff0c;禁止未經授權的轉載與改編。一、行業痛點&#xff1a;視頻質量檢測的現實挑戰在實時流媒體、在線教育、安防監控等領域&#xff0c;視頻質量直接影響用戶體驗與業務可信度。…

流式輸出阻塞原因及解決辦法

流式輸出不懂可看這篇文章&#xff1a;流式輸出&#xff1a;概念、技巧與常見問題 正常情況&#xff0c;如下代碼所示&#xff1a; async def event_generator():# 先輸出數字1yield "data: 1\n\n"# 然后每隔2秒輸出數字2&#xff0c;共輸出10次for i in range(10):…