Pinia是什么?
官網(wǎng)解釋:
Pinia 是 Vue 的存儲庫,它允許您跨組件/頁面共享狀態(tài)。
從官網(wǎng)的解釋不難看出,Pinia和Vuex的作用是一樣的,它也充當?shù)氖且粋€存儲數(shù)據(jù)的作用,存儲在Pinia的數(shù)據(jù)允許我們在各個組件中使用。
實際上,Pinia就是Vuex的升級版,官網(wǎng)也說過,為了尊重原作者,所以取名Pinia,而沒有取名Vuex,所以可以將Pinia比作為Vue3的Vuex。
Pinia的使用
1. 安裝pinia
npm install pinia
2. 引入pinia
vue3 中引入的使用
import { createApp } from 'vue'
import App from './App.vue'
import { createPinia } from 'pinia'
const app = createApp(App)
const pinia = createPinia()
app.use(pinia);
app.mount('#app')
vue2 中引入的使用
import { createPinia } from 'pinia'
const pinia = createPinia()
new Vue({
el: '#app',
// 其他選項...
// ...
pinia,
})
3. Store
3.1 定義store
創(chuàng)建 store/user.js
import { defineStore } from 'pinia'
export const useStore = defineStore({
id: 'user',
state: () => ({
count: 0,
username: '10個肉包子'
}),
getters: {},
actions: {},
})
3.2 使用store
<script setup>
import storeUser from "@/store/user";
const { counter } = storeUser();
console.log(123, count);
</script>
4. State
4.1 定義state
export default defineStore('user', {
state: () => ({
count: 0,
username: '10個肉包子'
}),
});
4.2 使用state
- 方法 1. 直接獲取
以 javascript 中的模塊導出的方式導出 store 數(shù)據(jù),state 中的數(shù)據(jù)均可通過變量.state 數(shù)據(jù)名獲取
<script setup>
import storeUser from "@/store/user";
const { counter } = storeUser();
console.log(123, count);
</script>
- 方法 2. 解構獲取
store 是一個 reactive 響應式對象,直接解構會使其失去響應式,類似 setup 中的 props,為了既可解構又可保持其響應式,可使用 storeToRefs,它將為每個 reactive 屬性創(chuàng)建 refs
<script setup>
import { storeToRefs } from "pinia";
import storeUser from "@/store/user";
const { count } = storeToRefs(storeUser());
console.log(123, count);
</script>
<template>
<div>
{{ count }}
</div>
</template>
4.3 修改 state
- 直接修改 state:
<script setup>
import storeUser from "@/store/user";
const store = storeUser();
store.count++
console.log(123, store);
</script>
- $patch 已對象修改
<template>
<div>index-{{store.count}}</div>
</template>
<script setup>
import storeUser from "@/store/user";
const store = storeUser();
store.$patch({
count: 3,
});
</script>
缺點: 如果只需修改 state 數(shù)據(jù)中的某一項,仍然需要將整個對象傳給 store。
或者
<template>
<div>index-{{store.count}}</div>
</template>
<script setup>
import storeUser from "@/store/user";
const store = storeUser();
store.$patch({
count: 3,
});
</script>
4.4 替換state
<template>
<div>index-{{store.count}}</div>
</template>
<script setup>
import storeUser from "@/store/user"
const store = storeUser()
store.$state = { count: 666, username: 'Paimon' }
</script>
4.5 重置state
一鍵回復默認的 state 數(shù)據(jù)
<template>
<div>index-{{store}}</div>
</template>
<script setup>
import storeUser from "@/store/user"
const store = storeUser()
store.$patch({
count: 3,
});
setTimeout(() => {
store.$reset()
}, 3000)
console.log(123, store)
</script>
5. Getters
5.1 獲取數(shù)據(jù)
建議使用尖頭函數(shù)
export const useStore = defineStore('user', {
state: () => ({
counter: 0,
}),
getters: {
doubleCount: (state) => state.counter * 2,
},
})
<template>
<div> {{ doubleCount }} </div>
<div> {{ counter }} </div>
</template>
<script setup>
import storeUser from "@/store/user"
import { storeToRefs } from 'pinia'
const store = storeUser();
const { doubleCount, counter } = storeToRefs(storeUser())
</script>
5.2 訪問其他 getters
訪問其他的 getter 需要使用 this, 注意:不能使用尖頭函數(shù)了
export const useStore = defineStore('user', {
state: () => ({
counter: 0,
}),
getters: {
doubleCount(state) {
return state.counter * 2
},
doublePlusOne() {
return this.doubleCount + 1
},
},
})
5.3 getters 傳遞參數(shù)
export const useStore = defineStore('user', {
getters: {
getUserById: (state) => {
return (userId) => state.users.find((user) => user.id === userId)
},
},
})</pre>
<pre data-language="plain" id="tPS6e" class="ne-codeblock language-plain" style="border: 1px solid #e8e8e8; border-radius: 2px; background: #f9f9f9; padding: 16px; font-size: 13px; color: #595959"><template>
<p>User 2: {{ store.getUserById(2) }}</p>
</template>
<script setup>
import storeUser from "../../store/user";
const store = storeUser();
</script>
注意: getters are not cached anymore 即 getters 不會被緩存,只能函數(shù)調(diào)用。
5.4 訪問其他的 getter
即想要哪個 getters 則調(diào)用哪個 getter,因為 pinia 沒有總?cè)肟?,?vuex 有本質(zhì)區(qū)別。
import { useOtherStore } from './other-store'
export const useStore = defineStore('main', {
state: () => ({
// ...
}),
getters: {
otherGetter(state) {
const otherStore = useOtherStore()
return state.localData + otherStore.data
},
},
})
5.5 使用 mapState 訪問 store 中的數(shù)據(jù)
import { mapState } from 'pinia'
import storeUser from "@/store/user";
export default {
computed: {
...mapState(storeUser, ['doubleCount'])
...mapState(storeUser, {
myOwnName: 'doubleCounter',
double: state => state.doubleCount,
}),
},
}
6. Actions
6.1 獲取方法
export const useStore = defineStore('user', {
state: () => ({
count: 0,
}),
actions: {
increment() {
this.count++
},
randomizeCounter() {
this.count = Math.round(100 * Math.random())
},
},
})
6.2 使用方法
- 同步的方式
<script setup>
import storeUser from "@/store/user"
const store = storeUser()
</script>
<template>
<button @click="store.increment()">增加</button>
</template>
- 異步的方式
import { mande } from 'mande'
const api = '@/api/users'
export const useUsers = defineStore('users', {
state: () => ({
userData: {},
}),
actions: {
async registerUser(login, password) {
try {
this.userData = await api.post({ login, password })
console.info(`Welcome back ${this.userData.name}!`)
} catch (error) {
console.error(error)
return error
}
},
},
})
Pinia 數(shù)據(jù)持久化插件
1. 安裝
npm i pinia-plugin-persist
2. 引入
Vue2中引入使用
import Vue from 'vue'
import vueCompositionApi from '@vue/composition-api'
import { createPinia } from 'pinia'
import piniaPersist from 'pinia-plugin-persist'
import App from './App.vue'
const pinia = createPinia()
pinia.use(piniaPersist)
Vue.use(vueCompositionApi)
Vue.use(pinia)
new Vue({
pinia,
render: h => h(App),
}).$mount('#app')
Vue3中引入使用
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import piniaPersist from 'pinia-plugin-persist'
const pinia = createPinia()
pinia.use(piniaPersist)
createApp({})
.use(pinia)
.mount('#app')
pinia的優(yōu)點
Vue2和Vue3都支持,這讓我們同時使用Vue2和Vue3的小伙伴都能很快上手。
Pinia中只有state、getter、action,拋棄了Vuex中的Mutation,pinia直接拋棄它了,這無疑減少了我們工作量。
Pinia中action支持同步和異步,Vuex不支持
良好的Typescript支持,Vue3都推薦使用TS來編寫,這個時候使用Pinia就非常合適了
-
無需再創(chuàng)建各個模塊嵌套了,Vuex中如果數(shù)據(jù)過多,我們通常分模塊來進行管理,稍顯麻煩,而pinia中每個store都是獨立的,互相不影響。 image
體積非常小,只有1KB左右。
pinia支持插件來擴展自身功能。
支持服務端渲染。
Pinia 與 Vuex對比
Pinia:State、Gettes、Actions(同步異步都支持)
Pinia圖解:

Vuex:State、Gettes、Mutations(同步)、Actions(異步)
Vuex圖解:

Pinia 當前最新版是 2.x,即支持 Vue2 也支持 Vue3;Vuex 當前最新版是 4.x,Vuex4 用于 Vue3,Vuex3 用于 Vue2。
