
Pinia是什么
Pinia 是 Vue 的存儲庫,允許您跨組件/頁面共享狀態(tài)。Pinia 這款產品最初是為了探索 Vuex 的下一個版本,整合了核心團隊關于 Vuex 5 的許多想法。最終,我們意識到 Pinia 已經實現(xiàn)了我們想要在 Vuex 5 中提供的大部分內容,因此決定將其作為 新的官方推薦。
Pinia特點
- 足夠輕量,Pinia 重約
1kb,甚至會忘記它的存在! - 去除
Mutation,Actions支持同步和異步(Actions一個頂倆,寫起來簡潔); - 無需手動注冊
Store,Store 僅需要時才自動注冊。如果從不使用,則永遠不會“注冊”(省心); - 沒有模塊嵌套,只有
Store的概念,Store 之間可以自由使用,更好的代碼分割; -
Vue2和Vue3都能支持; - 支持大型項目遷移期間,
Pinia和Vuex混合使用(貼心遷移); - 更完美的
typescript的支持; - 與
Vue devtools掛鉤,Vue2 和 Vue3 開發(fā)體驗更好; - 支持插件擴展功能;
- 支持模塊熱更新,無需加載頁面可以修改容器,可以保持任何現(xiàn)有的狀態(tài);
- 支持服務端渲染;
Vuex 與 Pinia 用哪個
Vuex 現(xiàn)在處于維護模式。它仍然可以工作,但不再添加新的功能。對于新的應用項目,建議使用 Pinia。Pinia 已經實現(xiàn)了我們想要在 Vuex 5 中提供的大部分內容,因此決定將其作為 新的官方推薦(注意:舊版網(wǎng)站沒有更新)

如何使用 Pinia
一、安裝
npm install pinia
vue2需要另外安裝
npm i pinia @vue/composition-api --save
二、定義 Store
新建 src/stores 目錄并在其下面創(chuàng)建 index.ts
Pinia的目錄通常被稱為 stores 而不是store, 這是為了強調Pinia使用多個store,而不是Vuex中的單個store,同時也有遷移期間Pinia和Vuex混合使用的考慮。
// src/stores/index.ts
// 引入Store定義函數(shù)
import { defineStore } from 'pinia'
// 定義Store實例并導出,useStore可以是任何東西,比如useUser, useCart
// 第一個參數(shù),唯一不可重復,字符串類型,作為倉庫ID 以區(qū)分倉庫
// 第二個參數(shù),以對象形式配置倉庫的state,getters,actions
export const useStore = defineStore('main', {
// state 推薦箭頭函數(shù),為了TS類型推斷
state: () => {
return {
name: '張三',
counter: 0
}
},
getters: {},
actions: {}
})
在 main.ts 中引入并掛載到根實例。
// src/main.ts
import { createApp } from 'vue'
import App from './App.vue'
import { createPinia } from 'pinia'
// 創(chuàng)建Vue應用實例
// 實例化 Pinia
// 以插件形式掛載Pinia實例
createApp(App).use(createPinia()).mount('#app')
vue2寫法
定義store同vue3,main.js中引入并掛在到跟實例代碼如下:
//main.js引入
// 引入pinia
import {createPinia,PiniaVuePlugin} from 'pinia'
Vue.use(PiniaVuePlugin)
const pinia = createPinia()//需要掛載在實例上
new Vue({
router,
pinia,
render: h => h(App)
}).$mount('#app')
vue2中如果報如下錯誤,

則需要在vue.config.js中增加以下配置:

三、State
1、訪問State
<template>
<div>
<button @click="handleClick">修改狀態(tài)數(shù)據(jù)</button>
<!-- 模板內不需要加.value -->
<p>{{store.name}}</p>
<!-- computed獲取 -->
<p>{{name}}</p>
<!-- 或者使用解構之后的 -->
<p>{{counter}}</p>
</div>
</template>
<script lang="ts" setup>
import { useStore } from '@/stores/index.ts'
// 使普通數(shù)據(jù)變響應式的函數(shù)
import { storeToRefs } from "pinia";
const store = useStore()
// 結合computed獲取
const name = computed(() => store.name)
// 解構并使數(shù)據(jù)具有響應式
const { counter } = storeToRefs(store);
// 點擊 + 1;
function handleClick() {
// ref數(shù)據(jù)這里需要加.value訪問
counter.value++;
}
</script>
2、修改State
1、單個參數(shù)修改 state
store.counter++
2、多個參數(shù)修改 state
store.$patch({
counter: store.counter + 1,
name: 'Abalam',
})
3、全部修改 state
store.$state = { counter: 666, name: 'Paimon' }
或
pinia.state.value = {}
3、重置State
將狀態(tài)重置為初始值
const store = useStore()
store.$reset()
4、vue2寫法
import { mapState } from 'pinia'
import { useCounterStore } from '../stores/counterStore'
export default {
computed: {
...mapState(useCounterStore, ['counter'])
// 或
...mapState(useCounterStore, {
myOwnName: 'counter',
double: store => store.counter * 2,
magicValue(store) {
return store.someGetter + this.counter + this.double
},
}),
},
}
四、Getters
getter 中的值有緩存特性,類似于computed,如果值沒有改變,多次使用也只會調用一次
1、定義Getters:
export const useStore = defineStore('main', {
state: () => ({
counter: 0,
}),
getters: {
doubleCount: (state) => state.counter * 2,
// 自動推導返回類型
doubleCount(state) {
return state.counter * 2
},
// 依賴getters返回參數(shù),則需要顯性的設置返回類型
doublePlusOne(): number {
return this.doubleCount + 1
},
},
})
2、使用Getters
<template>
<p>Double count is {{ store.doubleCount }}</p>
</template>
<script>
export default {
setup() {
const store = useStore()
return { store }
},
}
</script>
3、vue2寫法
import { mapState } from 'pinia'
import { useCounterStore } from '../stores/counterStore'
export default {
computed: {
...mapState(useCounterStore, ['doubleCount'])
// 或
...mapState(useCounterStore, {
myOwnName: 'doubleCounter',
double: store => store.doubleCount,
}),
},
}
五、Actions
Pinia 中刪除了 Mutation,Actions 支持同步和異步
1、定義 Actions
// 同步
export const useStore = defineStore('main', {
state: () => ({
counter: 0,
userData: null,
}),
actions: {
increment() {
this.counter++
},
randomizeCounter() {
this.counter = Math.round(100 * Math.random())
},
},
})
// 異步
import { mande } from 'mande'
const api = mande('/api/users')
export const useUsers = defineStore('users', {
state: () => ({
userData: null,
}),
actions: {
async registerUser(login, password) {
this.userData = await api.post({ login, password })
},
},
})
2、調用 Actions
1、可以直接調用 store 的任何方法
<script>
export default {
setup() {
const store = useStore()
store.randomizeCounter()
},
}
</script>
2、action 間的相互調用,直接用 this 訪問即可。
export const useUserStore = defineStore({'user',
actions: {
increment() {
this.counter++
},
increase() {
// 調用另一個 action 的方法
this.increment()
},
}
})
3、在 action 里調用其他 store 里的 action 也比較簡單,引入對應的 store 后即可訪問其內部的方法。
import { useAuthStore } from './auth-store'
export const useSettingsStore = defineStore('settings', {
state: () => ({
preferences: null,
}),
actions: {
async fetchUserPreferences() {
// 調用 auth-store store 里的 action 方法
const auth = useAuthStore()
if (auth.isAuthenticated) {
this.preferences = await fetchPreferences()
} else {
throw new Error('User must be authenticated')
}
},
},
})
3、vue2寫法
import { mapActions } from 'pinia'
import { useCounterStore } from '../stores/counterStore'
export default {
methods: {
...mapActions(useCounterStore, ['increment'])
// 或
...mapActions(useCounterStore, { myOwnName: 'doubleCounter' }),
},
}
總結
總得來說,Pinia 就是 Vuex 的官方替代版,可以更好的支持 Vue2,Vue3以及TypeScript。在 Vuex 的基礎上去掉了 Mutation、模塊嵌套等概念,語法更簡潔直接, 更符合 Vue3 的 Composition api,為 TypeScript 提供了更好的類型推導。以上是 Pinia.js 用法的一些介紹,Pinia.js 的內容還遠不止這些,更多內容及使用有待大家自己探索。Pinia文檔