Vue3之狀態(tài)管理器(Pinia)詳解及使用方式
注意:本文項目使用腳手架為 Vite;
1. 前言
Pinia 對比 Vuex
- Pinia 同時支持 Vue2 以及 Vue3 ,這讓同時使用兩個版本的小伙伴更容易上手;
- Pinia 中只存在 State,getter,action,剔除掉了 Vuex 中的 Mutation 及 Module;
- Pinia 中的 action 可同時支持同步任務(wù)、異步任務(wù);
- 更友好的支持了 TypeScript ,無需創(chuàng)建自定義復(fù)雜包裝器來支持 TypeScript,所有內(nèi)容都是類型化的,并且 API 的設(shè)計方式盡可能利用 TS 類型推斷;
- Pinia 在修改狀態(tài)的時候不需要通過其他 api,如:vuex 需通過 commit,dispatch 來修改,所以在語法上比 vuex 更容易理解和使用靈活;
- 由于去除掉了 Module ,無需再創(chuàng)建各個模塊嵌套了。Vuex 中,如果數(shù)據(jù)過多,通常會通過劃分模塊來進行管理,而 Pinia 中,每個 Store 都是獨立的,互不影響;
- 支持服務(wù)端渲染;
2. 安裝及引入
yarn add pinia // 或者使用 npm npm install pinia
安裝完 Pinia 包之后,需要在 main.js 文件中導(dǎo)入 createPinia 函數(shù)并將 Pinia 插件與 Vue 應(yīng)用程序綁定:
import { createApp } from 'vue'; import App from './App.vue'; // 引入 createPinia 函數(shù) import { createPinia } from 'pinia'; const app = createApp(App) // 使用 createPinia() 來創(chuàng)建 Pinia(根存儲),并應(yīng)用到整個應(yīng)用中 app.use(createPinia()); app.mount('#app');
使用 createPinia() 函數(shù)創(chuàng)建并初始化 Pinia 插件實例,將其與 Vue 應(yīng)用程序綁定使用 app.use(pinia)。
至此,我們就可以使用Pinia 來管理 Vue 應(yīng)用程序的狀態(tài)了。
最后,在 src 文件下創(chuàng)建一個 store 文件夾,并添加 store.js 文件。
3. Pinia的使用Store
Store
是使用 defineStore() 定義的,并且它需要一個唯一名稱,作為第一個參數(shù)傳遞。
這個名字 ,也被用作 id 是必須傳入的, Pinia 將用它來連接 store 和 devtools。
將返回的函數(shù)命名為 use… 是跨可組合項的約定,以使其符合使用習慣。
State
State 是 store 中存儲數(shù)據(jù)的地方。
通過定義 State,可以在 store 的任何位置訪問和修改數(shù)據(jù)。
// store/store.js import { defineStore } from 'pinia'; export const useMainStore = defineStore('main',{ state: () => { return { count:0 } } })
// views/home.vue <template> <div class="count">state:{{mainStore.count}}</div> <div class="btnWrap"> <button @click="resetStore">重 置</button> </div> </template> <script setup> import {useMainStore} from '@/store/store.js'; const mainStore = useMainStore(); console.log(mainStore.count) // 0 const resetStore = () => { mainStore.$reset() } </script>
效果:
Getters
Getter 用來獲取從 state 派生的數(shù)據(jù),類似于 Vue 組件中的 computed 計算屬性。
可通過 defineStore() 中的 getters 屬性來定義它們。
推薦使用箭頭函數(shù),并且它將接收 state 作為第一個參數(shù):
export const useStore = defineStore('main', { state: () => ({ count: 0, }), getters: { doubleCount: (state) => state.count * 2, }, })
Actions
Action 相當于組件中的方法。
它可以通過 defineStore() 中的 actions 屬性來定義;
Action 是一種將異步操作封裝在 store 中的方式,它是一個可被調(diào)用的函數(shù),也可接收參數(shù)并修改 store 中的狀態(tài)。
import { defineStore } from 'pinia' export const myStore = defineStore('myStore',{ state: () => ({ message: 'Hello', }), actions: { async fetchMessage() { const res = await fetch('http://127.0.0.1:5173/message') this.message = res.message }, }, })
4. 示例完整代碼
4.1 選項式寫法
// store/store.js import { defineStore } from 'pinia'; import axios from 'axios'; export const useMainStore = defineStore('main',{ state: () => { return { count:0, count2:0, list:[], } }, getters:{ doubleCount(){ return this.count*2; } }, actions:{ add(){ this.count++; }, update(val){ this.count = val.value; }, add2(){ this.count2++; }, // 異步 async getList(){ const res = await axios.get('https://api.oioweb.cn/api/common/history'); if(res.data.code == 200){ this.list = res.data.result || []; } }, } })
在組件中使用
<template> <div class="count">state:{{mainStore.count}}</div> <div class="count">getters:{{mainStore.doubleCount}}</div> <div class="btnWrap"> <button @click="resetStore">重 置</button> <button @click="addCount">增 加</button> <button @click="updateCount">更新至100</button> </div> <hr/> <div class="count">state:{{count2}}</div> <div class="btnWrap"> <button @click="add2">增 加</button> </div> <hr/> <h3>歷史上的今天</h3> <ul class="list"> <li v-for="(item,index) in mainStore.list" :key="index"> {{item.year}}年 - {{item.title}} </li> </ul> </template>
<script setup> import {useMainStore} from '@/store/store.js'; import {onMounted,ref} from 'vue'; import {storeToRefs} from 'pinia'; const mainStore = useMainStore(); const {count2} = storeToRefs(mainStore); const {add2} = mainStore; console.log(mainStore) const number = ref(100); const resetStore = () => { mainStore.$reset(); } const addCount = () => { mainStore.add(); }; const updateCount = () => { mainStore.update(number); } onMounted(() => { mainStore.getList(); }) </script>
效果:
分別觸發(fā) add2 兩次,addCount、getList 一次后的效果
4.2 組合式寫法
在組合式 API 中:
- ref() 相當于 state 屬性;
- computed() 相當于 getters;
- function() 相當于 actions;
// store/count.js import { defineStore } from 'pinia'; import {computed, ref} from 'vue'; import axios from 'axios'; // 第一個參數(shù)是應(yīng)用中 Store 的唯一 ID export const useCountStore = defineStore('count',() => { // state const count = ref(0); const count2 = ref(0); const list = ref([]); // getter const doubleCount = computed(() => { return count.value*2 }) // 同步action const add = () => { count.value++; } const update = (val) =>{ count.value = val.value; } const add2 = () => { count2.value++; } // 異步action const getList = async () => { const res = await axios.get('https://api.oioweb.cn/api/common/history'); if(res.data.code == 200){ list.value = res.data.result || []; } } return{ count, count2, doubleCount, list, add, update, add2, getList, } })
在組件中使用
<template> <div class="count">state:{{countStore.count}}</div> <div class="count">getters:{{countStore.doubleCount}}</div> <div class="btnWrap"> <button @click="resetStore">重 置</button> <button @click="addCount">增 加</button> <button @click="updateCount">更新至100</button> </div> <hr/> <div class="count">state:{{count2}}</div> <div class="btnWrap"> <button @click="add2">增 加</button> </div> <hr/> <h3>歷史上的今天</h3> <ul class="list"> <li v-for="(item,index) in countStore.list" :key="index"> {{item.year}}年 - {{item.title}} </li> </ul> </template>
<script setup> import {useCountStore} from '@/store/count.js'; import {onMounted,ref} from 'vue'; import {storeToRefs} from 'pinia'; const countStore = useCountStore(); const {count2} = storeToRefs(countStore); const {add2} = countStore; console.log(countStore) const number = ref(100); const resetStore = () => { countStore.$reset(); } const addCount = () => { countStore.add(); }; const updateCount = () => { countStore.update(number); } onMounted(() => { countStore.getList(); }) </script>
效果:
分別觸發(fā) add2 兩次,addCount、getList 一次后的效果
總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
vant的Loading加載動畫組件的使用(通過接口拿數(shù)據(jù)時顯示加載狀態(tài))
這篇文章主要介紹了vant的Loading加載動畫組件的使用,通過接口拿數(shù)據(jù)時顯示加載狀態(tài),本文通過實例代碼給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友參考下吧2024-01-01vue項目接口管理,所有接口都在apis文件夾中統(tǒng)一管理操作
這篇文章主要介紹了vue項目接口管理,所有接口都在apis文件夾中統(tǒng)一管理操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2020-08-08