掌握Vue.js中的狀態管理

掌握Vue.js中的狀態管理

用於 JavaScript 的 Vue 框架在構建使用者介面和單頁面應用程式(SPA)方面很受歡迎。為確保您的大型應用程式以最佳狀態執行,您需要牢牢掌握狀態管理,即管理和集中多個元件中的應用程式反應資料(狀態)的過程。

在 Vue 中,狀態管理長期以來一直依賴於 Vuex,這是一個為應用程式的所有元件提供集中儲存的庫。然而,Vue 生態系統的最新進展催生了 Vuex 的後繼者 Pinia。

Pinia 提供了一種更加輕量級、模組化和直觀的管理方法。它與 Vue 的反應系統和 Composition API 無縫整合,使開發人員可以輕鬆地以可擴充套件和可維護的方式管理和訪問共享狀態。

設定場景:Pinia 與 Vuex

作為 Vue 應用程式狀態管理的首選庫,Vuex 為應用程式的所有元件提供了一個集中儲存空間。然而,隨著 Vue 的發展,Pinia 代表了一種更現代的解決方案。讓我們探討一下它與 Vuex 的不同之處。

  • 應用程式介面(API)的不同 – 與 Vuex 相比,Pinia 的組成應用程式介面(Composition API)提供了更基本、更直觀的應用程式介面,使管理應用程式狀態變得更簡單。此外,它的結構與大多數 Vue 開發人員所熟悉的 Vue 選項 API 非常相似。
  • 型別支援 – 一直以來,許多 Vue 開發人員都在為 Vuex 有限的型別支援而苦惱。相比之下,Pinia 是一個完全型別化的狀態管理庫,消除了這些顧慮。它的型別安全性有助於防止潛在的執行時錯誤,提高程式碼的可讀性,並促進更流暢的擴充套件能力。
  • 反應性系統 – 兩個庫都利用了 Vue 的反應性系統,但 Pinia 的方法與 Vue 3 的 Composition API 更為接近。雖然反應性 API 功能強大,但在大型應用程式中管理複雜的狀態可能具有挑戰性。幸運的是,Pinia 簡單而靈活的架構減輕了 Vue 3 應用程式中狀態管理的麻煩。Pinia 的儲存模式可讓您定義一個儲存空間,用於管理應用程式狀態的特定部分,簡化其組織並在元件間共享。
  • 輕量級特性 – Pinia 只有 1 KB,可無縫整合到您的開發環境中,其輕量級特性可提高您的應用程式效能和載入時間。

如何用 Pinia 建立 Vue 專案

要在 Vue 專案中整合 Pinia,請使用 Vue CLI 或 Vite 初始化專案。專案初始化後,可以通過 npm 或 yarn 將 Pinia 作為依賴關係安裝。

  1. 使用 Vue CLI 或 Vite 建立一個新的 Vue 專案。然後,按照提示設定專案。
    Plain text
    Copy to clipboard
    Open code in new window
    EnlighterJS 3 Syntax Highlighter
    // Using Vue CLI
    vue create my-vue-ap
    // Using Vite
    npm create vite@latest my-vue-app -- --template vue
    // Using Vue CLI vue create my-vue-ap // Using Vite npm create vite@latest my-vue-app -- --template vue
    // Using Vue CLI
    vue create my-vue-ap
    // Using Vite
    npm create vite@latest my-vue-app -- --template vue
  2. 將目錄更改為新建立的專案資料夾:
    Plain text
    Copy to clipboard
    Open code in new window
    EnlighterJS 3 Syntax Highlighter
    cd my-vue-app
    cd my-vue-app
    cd my-vue-app
  3. 將 Pinia 作為依賴項安裝到您的專案中。
    Plain text
    Copy to clipboard
    Open code in new window
    EnlighterJS 3 Syntax Highlighter
    // Using npm
    npm install pinia
    // Using yarn
    yarn add pinia
    // Using npm npm install pinia // Using yarn yarn add pinia
    // Using npm
    npm install pinia
    // Using yarn
    yarn add pinia
  4. 在主入口檔案(通常是 main.jsmain.ts)中,匯入 Pinia 並告訴 Vue 使用它:
    Plain text
    Copy to clipboard
    Open code in new window
    EnlighterJS 3 Syntax Highlighter
    import { createApp } from 'vue';
    import { createPinia } from 'pinia';
    import App from './App.vue';
    const app = createApp(App);
    app.use(createPinia());
    app.mount('#app');
    import { createApp } from 'vue'; import { createPinia } from 'pinia'; import App from './App.vue'; const app = createApp(App); app.use(createPinia()); app.mount('#app');
    import { createApp } from 'vue';
    import { createPinia } from 'pinia';
    import App from './App.vue';
    const app = createApp(App);
    app.use(createPinia());
    app.mount('#app');

    在 Vue 專案中安裝並設定好 Pinia 後,就可以定義並使用儲存來進行狀態管理了。

如何在 Pinia 中建立 Pinia

Store 是 Pinia 驅動的 Vue 應用程式中狀態管理的支柱。它可以幫助您以協調一致的方式管理應用程式範圍內的資料。儲存是您定義、儲存和管理應用程式各元件間共享資料的地方。

這種集中化非常重要,因為它可以構建和組織應用程式的狀態變化,使資料流更可預測,除錯更簡單。

此外,Pinia 中的儲存不僅僅是儲存狀態: Pinia 附帶的功能可讓您通過操作更新狀態,並通過獲取器計算派生狀態。這些內建功能有助於提高程式碼庫的效率和可維護性。

下面的示例說明了如何在專案的 src/store.js 檔案中建立一個基本的 Pinia store。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
import { defineStore } from 'pinia';
export const useStore = defineStore('main', {
state: () => ({
count: 0,
}),
actions: {
increment() {
this.count++;
},
},
getters: {
doubleCount: (state) => state.count * 2,
},
});
import { defineStore } from 'pinia'; export const useStore = defineStore('main', { state: () => ({ count: 0, }), actions: { increment() { this.count++; }, }, getters: { doubleCount: (state) => state.count * 2, }, });
import { defineStore } from 'pinia';
export const useStore = defineStore('main', {
state: () => ({
count: 0,
}),
actions: {
increment() {
this.count++;
},
},
getters: {
doubleCount: (state) => state.count * 2,
},
});

如何訪問元件中的儲存狀態

與 Vuex 相比,Pinia 的狀態訪問和管理方法更加直觀,尤其是如果您熟悉 Vue 3 的 Composition API。該 API 是一組能夠在元件中包含反應性和可組合邏輯的 API。

請看下面的程式碼。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<template>
<div>{{ store.count }}</div>
</template>
<script>>
import { useStore } from './store';
export default {
setup() {
const store = useStore();
return { store };
},
}
</script>
<template> <div>{{ store.count }}</div> </template> <script>> import { useStore } from './store'; export default { setup() { const store = useStore(); return { store }; }, } </script>
<template>
<div>{{ store.count }}</div>
</template>
<script>>
import { useStore } from './store';
export default {
setup() {
const store = useStore();
return { store };
},
}
</script>

在上述程式碼段中, <template> 標籤包含了元件定義的 HTML 標記。要顯示 Pinia store 中的 count 屬性值,需要使用 Vue 的資料繫結語法,即 {{ count }}

useStore 函式提供了對 Pinia store 的訪問,因此您可以使用 import { useStore } 從 store.js 中 import { useStore } from './store';

作為 Vue 3 的 Composition API 的一項功能,setup 函式定義了元件的反應狀態和邏輯。然後在該函式中呼叫 useStore() 訪問 Pinia store。

接著,const count = store.count 訪問儲存的 count 屬性,使其在元件中可用。

最後,setup 返回 count,允許模板對其進行渲染。Vue 的反應性系統意味著,只要 store 中的 count 發生變化,元件的模板就會更新其值。

下面是輸出的截圖。

載入 Pinia store 演示模板

在瀏覽器中載入 Pinia store 演示模板的截圖。

此示例說明了 Pinia 的優勢:

  • 簡單 – Pinia 允許直接訪問 store 的狀態,無需對映函式。相比之下,Vuex 需要 mapState (或類似的助手)才能實現相同的訪問。
  • 直接訪問儲存 – Pinia 可讓您直接訪問狀態屬性(如 store.count),從而使您的程式碼更易讀、更易懂。與此同時,Vuex 通常需要 getter 來訪問即使是基本的屬性,從而增加了複雜性,降低了可讀性。
  • Composition API 相容性 – 正如設定方法所展示的,Pinia 與 Composition API 的整合與現代 Vue 開發特別吻合,提供了更加統一的編碼體驗。

如何使用 Pinia 修改狀態

在 Pinia 中,您可以使用動作來修改 store 的狀態,這比 Vuex 的突變更靈活。請看下面的函式呼叫,它會增加狀態的 count 屬性:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
store.increment(); // Increments the count
store.increment(); // Increments the count
store.increment(); // Increments the count

另一方面,Vuex 的等價方法除了定義至少一個動作外,還需要定義一個突變:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
mutations: {
increment(state) {
state.count++;
},
},
actions: {
increment({ commit }) {
commit('increment');
},
}
mutations: { increment(state) { state.count++; }, }, actions: { increment({ commit }) { commit('increment'); }, }
mutations: {
increment(state) {
state.count++;
},
},
actions: {
increment({ commit }) {
commit('increment');
},
}

Pinia 操作及其對應的 Vuex 程式碼體現了這兩個庫程式碼複雜度之間的重要差異。讓我們進一步探討這些差異:

  • 直接狀態突變與間接狀態突變 – 正如 increment 操作所展示的,Pinia 操作會直接改變儲存的狀態。在 Vuex 中,您只能使用突變來改變狀態,而突變必須通過操作提交。這種流程分離確保了狀態更改的可追蹤性,但它比類似的 Pinia 操作更加複雜和僵化。
  • 非同步與同步操作 – Vuex 的突變始終是同步的,不能包含非同步程序,而 Pinia 操作則可以包含同步和非同步程式碼。因此,您可以直接在動作中執行 API 呼叫或其他非同步操作,從而使程式碼庫更精簡、更簡潔。
  • 簡化語法 – Vuex 通常需要定義突變並呼叫操作來提交它們。Pinia 則不需要這樣。在操作中突變狀態的功能減少了模板程式碼,使現有程式碼更加簡潔明瞭。在 Vuex 中,基本的狀態更新需要定義一個動作和一個突變,即使該動作只是提交突變。

從 Vuex 到 Pinia 的過渡

過渡到 Pinia 可以在簡單性、靈活性和可維護性方面帶來諸多好處,但需要仔細規劃和考慮,以確保成功實施。

在轉換之前,請確保:

  1. 熟悉 Pinia 與 Vuex 架構、狀態管理模式和 API 之間的差異。瞭解這些差異對於有效重構程式碼和充分利用 Pinia 的功能至關重要。分析並重構你的 Vuex 狀態、操作、
  2. 突變和獲取器,以適應 Pinia 的結構。請記住,在 Pinia 中,您可以將狀態定義為函式。你可以直接用動作來改變狀態,也可以更順利地實現獲取器。
    計劃如何過渡 Vuex 儲存模組。Pinia 使用模組的方式與 Vuex 不同,但您仍可將儲存結構用於類似目的。
  3. 利用 Pinia 改進的 TypeScript 支援。如果您的專案使用了 TypeScript,請考慮使用 Pinia 增強的型別推斷和鍵入功能,以獲得更好的型別安全性和開發人員體驗。
  4. 修改測試策略,以適應狀態管理的變化。這一過程可能涉及更新單元測試和整合測試中模擬儲存或操作的方式。
  5. 考慮過渡對專案結構和組織的影響。考慮命名約定以及跨元件匯入和使用儲存的方式等因素。
  6. 確保與其他庫的相容性。檢查轉換可能影響的任何必要更新或依賴關係變化。
  7. 評估任何效能變化。Pinia 通常比 Vuex 更輕量級,但在過渡期間和之後,請繼續監控應用程式的效能,以確保沒有任何問題。

將儲存從 Vuex 轉換到 Pinia 需要幾個步驟,以適應兩者結構和 API 的差異。請看前面的 Pinia store。

在 Vuex store.js 檔案中,相同的儲存顯示如下。

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
export default new Vuex.Store({
state: {
count: 0,
},
mutations: {
increment(state) {
state.count++;
},
},
actions: {
increment(context) {
context.commit('increment');
},
},
getters: {
doubleCount(state) {
return state.count * 2;
},
},
});
import Vue from 'vue'; import Vuex from 'vuex'; Vue.use(Vuex); export default new Vuex.Store({ state: { count: 0, }, mutations: { increment(state) { state.count++; }, }, actions: { increment(context) { context.commit('increment'); }, }, getters: { doubleCount(state) { return state.count * 2; }, }, });
import Vue from 'vue';
import Vuex from 'vuex';
Vue.use(Vuex);
export default new Vuex.Store({
state: {
count: 0,
},
mutations: {
increment(state) {
state.count++;
},
},
actions: {
increment(context) {
context.commit('increment');
},
},
getters: {
doubleCount(state) {
return state.count * 2;
},
},
});

與之前的 Pinia store 一樣,這個 Vuex 示例包含一個 state 物件,其單一的 count 屬性初始化為 0

getters 物件包含直接突變狀態的方法,而動作物件的方法則提交增量突變。

然後,getters 物件包含 doubleCount 方法,該方法將 count 狀態乘以 2 並返回結果。

正如這段程式碼所展示的,在 Pinia 中實現儲存與 Vuex 有幾個明顯的不同之處:

  • 初始化 – Pinia 不需要 Vue.use()
  • 結構 – 在 Pinia 中,狀態是一個返回物件的函式,因此可以更好地支援 TypeScript 和反應性。
  • 動作(Actions)– Pinia 中的動作是直接改變狀態的方法,無需突變,從而簡化了程式碼。
  • Getters – 與 Vuex 類似,Pinia 中的 Getters 定義在儲存定義中,可以直接訪問狀態。

如何在元件中使用儲存

使用 Vuex 時,您可以這樣使用儲存:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<template>
<div>{{ doubleCount }}</div>
<button @click="increment">Increment</button>
</template>
<script>
import { mapGetters, mapActions } from 'vuex';
export default {
computed: {
...mapGetters(['doubleCount']),
},
methods: {
...mapActions(['increment']),
},
};
</script>
<template> <div>{{ doubleCount }}</div> <button @click="increment">Increment</button> </template> <script> import { mapGetters, mapActions } from 'vuex'; export default { computed: { ...mapGetters(['doubleCount']), }, methods: { ...mapActions(['increment']), }, }; </script>
<template>
<div>{{ doubleCount }}</div>
<button @click="increment">Increment</button>
</template>
<script>
import { mapGetters, mapActions } from 'vuex';
export default {
computed: {
...mapGetters(['doubleCount']),
},
methods: {
...mapActions(['increment']),
},
};
</script>

對於 Pinia 來說,用法變成了:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
<template>
<div>{{ store.doubleCount }}</div>
<button> @click="store.increment">Increment</button>
</template>
<script>>
import { useStore } from '/src/store';
export default {
setup() {
const store = useStore();
return {
store,
};
},
};
</script>
<template> <div>{{ store.doubleCount }}</div> <button> @click="store.increment">Increment</button> </template> <script>> import { useStore } from '/src/store'; export default { setup() { const store = useStore(); return { store, }; }, }; </script>
<template>
<div>{{ store.doubleCount }}</div>
<button> @click="store.increment">Increment</button>
</template>
<script>>
import { useStore } from '/src/store';
export default {
setup() {
const store = useStore();
return {
store,
};
},
};
</script>

Pinia store 轉換

Pinia store 轉換。

本示例涵蓋基本轉換。對於更復雜的 Vuex store,尤其是使用模組的 store,轉換將涉及更詳細的重組,以與 Pinia 的架構保持一致。

如何部署 Vue 應用程式

在部署之前,請註冊免費試用 Kinsta 的應用程式託管服務。您將在 Dockerfile 的幫助下部署應用程式。

在專案根目錄下建立一個 Dockerfile,並貼上以下內容:

Plain text
Copy to clipboard
Open code in new window
EnlighterJS 3 Syntax Highlighter
FROM node:latest
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY ./ .
CMD ["npm", "run", "start"]
FROM node:latest WORKDIR /app COPY package*.json ./ RUN npm install COPY ./ . CMD ["npm", "run", "start"]
FROM node:latest
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY ./ .
CMD ["npm", "run", "start"]

這段程式碼指示 Kinsta 的 Docker 引擎安裝 Node.js ( FROM node:late )、建立工作目錄 ( WORKDIR /app )、從 package.json 檔案中安裝 node 模組 ( RUN npm install ),並設定 Vue 應用程式啟動時將呼叫的啟動 ( CMD ["npm", "run", "start" ])命令。COPY 命令會將指定的檔案或目錄複製到工作目錄中。

然後,將程式碼推送到首選的 Git 提供商(Bitbucket、GitHub 或 GitLab)。軟體倉庫準備就緒後,請按照以下步驟將應用程式部署到 Kinsta:

  1. 登入或建立賬戶,檢視 MyKinsta 面板。
  2. 使用 Git 提供商授權 Kinsta。
  3. 選擇左側邊欄上的 Application,然後單擊 “Add Application” 按鈕。
  4. 在出現的模態中,選擇要部署的版本庫。如果有多個分支,可以選擇所需的分支併為應用程式命名。
  5. 從可用的資料中心位置中選擇一個。
  6. 選擇你的構建環境,然後選擇使用 Dockerfile 來設定容器映像
  7. 如果你的 Dockerfile 不在版本庫的根目錄中,請使用 Context 來指明其路徑,然後單擊 “Continue“。
  8. 你可以將 Start command 留空。Kinsta 會使用 npm start 啟動應用程式。
  9. 選擇最適合您應用程式的 pod 大小和例項數量,然後單擊 “Continue“。
  10. 填寫信用卡資訊,然後單擊 Create application

除了應用程式託管,您還可以選擇將 Vue 應用程式作為靜態網站部署到靜態網站託管中。

小結

從 Vuex 到 Pinia 的過渡標誌著 Vue 生態系統中狀態管理的重大演進。Pinia 的簡單性、改進的 TypeScript 支援以及與 Vue 3 的 Composition API 的一致性使其成為現代 Vue 應用程式的理想選擇。

評論留言