在大型應用程式中,由於多個狀態分散在許多組件以及它們之間的交互,狀態管理通常變得複雜。人們常常忽略 Vue 實例中的事實來源是原始資料物件 - Vue 實例只是代理對它的訪問。因此,如果您有一個狀態應該由多個實例共享,則應避免重複它並通過身份共享它。
如果您希望組件共享狀態,建議的方法是 Pinia。在深入了解之前,請查看其文檔。當與 Vue 開發者工具 瀏覽器擴充功能(如 Time Travel 偵錯)一起使用時,它具有出色的功能。
我們不會詳細介紹如何配置或使用 Pinia,因為它有很棒的文檔。相反,我們將向您展示在 Quasar 專案中使用它時的資料夾結構。
當您搭建 Quasar 專案資料夾時,您可以選擇新增 Pinia。它將為您建立所有必要的配置。例如,建立 /src/stores
,它處理您需要的所有 Pinia 相關程式碼。
如果您在專案建立期間未選擇 Pinia 選項,但稍後想要新增它,那麼您只需檢查下一節並建立 src/stores/index.[js|ts]
檔案(當您執行 quasar new store <name>
時,它會自動建立)。
import { store } from 'quasar/wrappers'
import { createPinia } from 'pinia'
/*
* If not building with SSR mode, you can
* directly export the Store instantiation;
*
* The function below can be async too; either use
* async/await or return a Promise which resolves
* with the Store instance.
*/
export default store((/* { ssrContext } */) => {
const pinia = createPinia()
// You can add Pinia plugins here
// pinia.use(SomePiniaPlugin)
return pinia
})
新增 Pinia store
通過 $ quasar new
命令,使用 Quasar CLI 可以輕鬆新增 Pinia store。
$ quasar new store <store_name> [--format ts]
它將在 /src/stores
中建立一個資料夾,名稱為上述命令中的“store_name”。它將包含您需要的所有樣板。
假設您要建立一個“counter” Pinia store。您發出 $ quasar new store counter
。然後您會注意到新建立的 /src/stores/counter.[js|ts]
檔案。
Pinia store 範例
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('counter', {
state: () => ({
counter: 0,
}),
getters: {
doubleCount: (state) => state.counter * 2,
},
actions: {
increment() {
this.counter++;
},
},
})
我們已經建立了新的 Pinia store,但我們還沒有在我們的應用程式中使用它。在 Vue 檔案中
<template>
<div>
<!-- Option 1 -->
<div>Direct store</div>
<!-- Read the state value directly -->
<div>{{ store.counter }}</div>
<!-- Use getter directly -->
<div>{{ store.doubleCount }}</div>
<!-- Manipulate state directly -->
<q-btn @click="store.counter--">-</q-btn>
<!-- Use an action -->
<q-btn @click="store.increment()">+</q-btn>
</div>
<div>
<!-- Option 2 -->
<div>Indirect store</div>
<!-- Use the computed state -->
<div>{{ count }}</div>
<!-- Use the computed getter -->
<div>{{ doubleCountValue }}</div>
<!-- Use the exposed function -->
<q-btn @click="decrementCount()">-</q-btn>
<!-- Use the exposed function -->
<q-btn @click="incrementCount()">+</q-btn>
</div>
<div>
<!-- Option 3 -->
<div>Destructured store</div>
<!-- Use the destructured state -->
<div>{{ counter }}</div>
<!-- Use the destructured getter -->
<div>{{ doubleCount }}</div>
<!-- Manipulate state directly-->
<q-btn @click="counter--">-</q-btn>
<!-- Use an action -->
<q-btn @click="increment()">+</q-btn>
</div>
</template>
<script>
import { computed } from 'vue';
import { useCounterStore } from 'stores/counter';
import { storeToRefs } from 'pinia';
export default {
setup() {
const store = useCounterStore();
// Option 2: use computed and functions to use the store
const count = computed(() => store.counter);
const doubleCountValue = computed(() => store.doubleCount);
const incrementCount = () => store.increment(); // use action
const decrementCount = () => store.counter--; // manipulate directly
// Option 3: use destructuring to use the store in the template
const { counter, doubleCount } = storeToRefs(store); // state and getters need "storeToRefs"
const { increment } = store; // actions can be destructured directly
return {
// Option 1: return the store directly and couple it in the template
store,
// Option 2: use the store in functions and compute the state to use in the template
count,
doubleCountValue,
incrementCount,
decrementCount,
// Option 3: pass the destructed state, getters and actions to the template
counter,
increment,
doubleCount,
};
},
};
</script>
有關定義 Pinia store 的更多資訊,請參閱此處。
在 Pinia store 中存取路由
只需在 Pinia store 中使用 this.router
即可存取路由。
這是一個範例
import { defineStore } from 'pinia'
export const useWhateverStore = defineStore('whatever', {
// ...
actions: {
whateverAction () {
this.router.push('...')
}
}
}