Pinia or Vuex?

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持久化插件用法

pinia的優(yōu)點

  1. Vue2和Vue3都支持,這讓我們同時使用Vue2和Vue3的小伙伴都能很快上手。

  2. Pinia中只有state、getter、action,拋棄了Vuex中的Mutation,pinia直接拋棄它了,這無疑減少了我們工作量。

  3. Pinia中action支持同步和異步,Vuex不支持

  4. 良好的Typescript支持,Vue3都推薦使用TS來編寫,這個時候使用Pinia就非常合適了

  5. 無需再創(chuàng)建各個模塊嵌套了,Vuex中如果數(shù)據(jù)過多,我們通常分模塊來進行管理,稍顯麻煩,而pinia中每個store都是獨立的,互相不影響。
    image
  6. 體積非常小,只有1KB左右。

  7. pinia支持插件來擴展自身功能。

  8. 支持服務端渲染。

Pinia 與 Vuex對比

Pinia:State、Gettes、Actions(同步異步都支持)

Pinia圖解:


image

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

Vuex圖解:


image

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

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

相關閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容