banner
isolcat

isolcat

I am not afraid of storms, for I am learning how to sail my ship
github

2k字輕鬆入門Pinia,猴子都可以看懂的教程

前言#

image.png

都什麼年代了,還在用傳統狀態管理庫?快來學習Pinia吧!

Pinia 這個名字的來源也很有意思,在西班牙語中,Pinia 是菠蘿這個詞最相似的英語發音,而一個菠蘿是由一組組單獨的花,結合在一起的,創造了多個水果,與 stores 類似,每一個都是獨立的,但最終都會有著聯繫

當我們點開vuex的 github 庫的時候,會看見官方的提示Pinia is now the new default,而作為 Vue 的新一代的官方狀態管理庫,Pinia 有著更多優勢,解決了很多 Vuex 所留下的問題,在編寫的時候,會更有邏輯性,接下來就讓我們去試著了解一下吧!

Pinia 優點#

  • vue3 vue2 均支持
  • 拋棄了 Mutation 的操作,只有stategetteraction
  • Actions支持同步和異步
  • 支持使用插件擴展 Pinia 功能
  • 不需要嵌套模塊,更加符合 Vue3 的Composition api
  • 支持 typescript
  • 代碼更加的簡潔

用 Pinia 方式創建一個 store#

我們先快速創建一個空項目,再安裝Pinia:

npm install pinia

雖然 Pinia 支持 vue2,但如果你使用的 vue 版本低於Vue2.7, 還需獨立安裝 composition api: @vue/composition-api(這裡建議直接升到 Vue2.7,相較於 Vue3 來說,跨度不會太大,但對 Vue 的生態支持的更好)

main.ts中對 Pinia 進行引入:

import { createApp } from 'vue'
import { createPinia } from 'pinia'

import App from './App.vue'


const app = createApp(App)

app.use(createPinia())

app.mount('#app')

接著,我們在src/store中創建counter.ts,並寫下基礎模板:

import { defineStore } from "pinia";

export const mainStore = defineStore('main', {
  state: () => {
    return {
      helloWord: 'HelloWorld'
    }
  },
  getters: {

  },
  actions: {

  }
})

創建好倉庫mainStore(倉庫名)後,我們將在組件中進行使用

<template>
  <div class="">{{ store.helloWord }}</div>
</template>

<script lang="ts" setup>
import { mainStore } from "../store/counter";
const store = mainStore();
</script>

<style scoped></style>

當頁面顯示出helloWorld後,則說明store創建成功

Pinia 改變數據狀態#

我們在counter.ts中的state添加數據count

import { defineStore } from "pinia";

export const mainStore = defineStore('main', {
  state: () => {
    return {
      count: 0,
      helloWord: 'HelloWorld'
    }
  },
  getters: {

  },
  actions: {

  }
})

做一個擁有點擊事件按鈕:

<template>
  <div>
    <button @click="handleClick">修改數據狀態</button>
  </div>
</template>

<script setup lang="ts">
import { mainStore } from "@/stores/counter";
const store = mainStore();
const handleClick = () => {
  store.count++;
};
</script>

將其引入App.vue後,對數據狀態進行修改:

<template>
  <Click />
  <CountButton />
</template>

<script lang="ts" setup>
import Click from "./components/Click.vue";
import CountButton from "./components/CountButton.vue";
</script>

這時候便發現點擊按鈕後會改變count的值了

在實際開發的過程中,我們往往需要多次調用store中的數據,如果每次改變其值都需要{{store.****}}未免太麻煩了,我們對其進行解構:

<template>
  <div class="">{{ store.helloWord }}</div>
  <div class="">{{ store.count }}</div>
  <hr />
  <!-- 解構後可以直接省略掉store,減少了代碼量 -->
  <div>{{ helloWord }}</div>
  <div>{{ count }}</div>
</template>

<script lang="ts" setup>
import { mainStore } from "../store/counter";
import { storeToRefs } from "pinia";
const store = mainStore();

// 進行解構
const { helloWord, count } = storeToRefs(store);
</script>

<style scoped></style>

注意,解構必須要用到storeToRefs()函數!

PInia 修改數據的四種方法#

  • 第一種方法:
const handleClick = () => {
  store.count++;
};
  • 第二種方式$patch
const handleClickPatch=()=>{
	store.$patch({
		count:store.count+2
	})
}

第二種方法寫起來雖然沒有第一種簡單,但更加適合於多個數據的改變

  • 第三種方式 $patch 傳遞函數
const handleClickMethod = () => {
  // 這裡的state就是指代的倉庫中的state
  store.$patch((state) => {
    state.count++;
    state.helloWord = state.helloWord === "jspang" ? "Hello World" : "jspang";
  });
};
  • 第四種方式 action

當業務邏輯很複雜的時候,就將方法寫在store中的action

actions: {
    changeState() {
      this.count++
      this.helloWord = 'jspang'
    }
  }

Getters#

與 vuex 中的 getters 是差不多的,相當於 vue 中的計算方法。但當我們查看 vuex 文檔,會發現這個提示:

注意

從 Vue 3.0 開始,getter 的結果不再像計算屬性一樣會被緩存起來。這是一個已知的問題,將會在 3.1 版本中修復。詳情請看 PR #1878

直到現在,這個提示仍然存在,這也是我更推薦使用Pinia的原因之一。

Pinia 中的Getters本身內部是可以進行緩存的,用代碼來驗證:

getters: {
    phoneHidden(state) {
      // 正則表達式
      console.log('getters被調用');
      return state.phone.toString().replace(/^(\d{3})\d{4}(\d{4})$/, '$1****$2')
    }
  },

我們在組件中兩次調用 phone (數據),點開控制台進行查看

image.png

是只會出現一次的,證實了其具有緩存功能,這對於性能優化是有好處的

Pinia 中的 stores 互相調用#

在實際開發中,往往不會只用到一個倉庫的,倉庫和倉庫之間通常會有一個調度,這裡我們再創建一個倉庫:

import { defineStore } from "pinia";

export const nameStore = defineStore('name', {
    state: () => {
        return {
            list: ['小紅', '小美', '胖丫']
        }
    }
})

接著我們在counter.ts中導入,import {jspangStore} from './jspang',在action中進行調用:

 actions: {
    getList() {
      console.log(nameStore().list);
    }
  }

查看控制台,發現已經成功調用了另一個倉庫的state,成功做到了store之間的相互調用

支持 VueDevtools#

Pinia 雖然作為一個新人,但已經全面支持 VueDevtools 了,這對於我們在實際項目開發中的調試有著很大的幫助,值得一提的是,在打開 VueDevtools 時,我們可以看見一個很俏皮的菠蘿的 logoimage.png

在開發時候的心情都更好了哈哈哈

注意:如果你使用的是 Pinia v2,請升級你的Vue Devtools到 v6 版本

Pinia 實戰:修改頭像#

說了這麼多,不如來實戰一下,在實際的項目中運用一下pinia。開發背景:在我們製作網頁的時候,往往會涉及到註冊功能,用戶頭像在登錄前登錄後是不一樣的。如果只寫一個點擊事件來修改頭像的話,一旦刷新或是進行了頁面的跳轉便會恢復原樣,狀態無法得到保存,這時候我們就可以請出我們的 pinia 了

注意,為了 pinia 中的數據持久化存儲(存到 localstorage 或 sessionstorage 中),我們還需要安裝一個插件:pinia-plugin-persist,他能夠讓我們的操作更加方便,這裡便不展開贅述了,詳細可以參考官方文檔

1. 創建倉庫#

第一步還是先創建倉庫(這裡默認你已經配置好了相關環境),創建store/user.ts,具體代碼如下:

import { defineStore } from 'pinia';

export const mainStore = defineStore('main', {
    state: () => {
        return {
            login: require('../assets/images/login.png')
        }
    },
    // 開啟持久化
    persist: {
        enabled: true,
        strategies: [
            { storage: localStorage, paths: ['login'] }
        ],
    },
    getters: {

    },
    actions: {
       
    }
})

成功創建後,我們便將用戶頭像存儲在了store中,接下來便是將其在組件中使用

2. 組件中調用#

<!-- 頭像 -->
<a class="face" href="#/login">
   <img :src="store.login" alt="" />
</a>

打開瀏覽器查看:image.png

成功調用!接下來便是最重要的一步,實現登錄後頭像能夠順利存儲在本地。我們這時候選擇直接在actions中添加修改數據的操作:

actions: {
        changeHeadShot() {
            console.log('數據存儲成功');
            this.login = require('../assets/images/head.png')
        }
    }

將我們寫好的action在組件中運用:

<template>
  <!-- 省略不必要的代碼 (這裡用的是vant的組件)-->
      <van-col span="8" @click="headerC">
        <van-button class="btn2" plain hairlin type="primary" to="/">
          <p class="text">登錄</p>
        </van-button>
      </van-col>
</template>

<script setup>
//引入store
import { mainStore } from '@/store/user'
const login = mainStore()

//實現點擊修改頭像的函數
function headerC() {
  login.changeHeadShot()
}
</script>

<style scoped>
/* 省略不必要的代碼 */
</style>

接下來便是 "見證奇跡" 的時刻:我們點擊登錄按鈕後,頭像將會發生改變:image.png

這時候無論我們怎麼刷新,頭像都不會出現變化了,我們打開控制台點開應用中的存儲,可以看見我們的登錄頭像已經存儲在本地的瀏覽器中:

image.png

結語#

總而言之,無論你是否之前接觸過 Vuex,我都更推薦你使用Pinia,他相較於 Vuex,有著更好的兼容性,在 Vuex 的基礎上去掉了Mutation,讓語法更加簡練,更符合 Vue3 的Composition api,Vuex 也不會再進行更新,現在已經處於維護狀態了,而 Pinia 作為下一代的 Vuex,又有什麼理由不去學習和使用呢?

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。