在大型應用程式中,由於多個狀態片段分散在許多組件及其互動之間,狀態管理通常變得複雜。人們常常忽略 Vue 實例中的真理來源是原始資料物件 - Vue 實例只是代理對它的存取。因此,如果您有一個應由多個實例共用的狀態片段,則應避免重複它並通過身份共用它。
如果您希望組件共用狀態,建議使用 Pinia。在深入研究之前,請先查看其文件。當與 Vue 開發者工具 瀏覽器擴充功能(如時間旅行偵錯)一起使用時,它有一個很棒的功能。
我們不會詳細介紹如何配置或使用 Pinia,因為它有很棒的文件。相反,我們將只向您展示在 Quasar 專案中使用它時資料夾結構的外觀。
當您搭建 Quasar 專案資料夾時,您可以選擇添加 Pinia。它將為您建立所有必要的配置。例如,建立處理您需要的所有 Pinia 相關程式碼的 /src/stores
。
如果您在專案建立期間未選擇 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 商店
通過 $ quasar new
命令,使用 Quasar CLI 添加 Pinia 商店很容易。
$ quasar new store <store_name> [--format ts]
它將在 /src/stores
中建立一個資料夾,並以來自上述命令的 “store_name” 命名。它將包含您需要的所有樣板。
假設您要建立一個 “counter” Pinia 商店。您發出 $ quasar new store counter
。然後您會注意到新建立的 /src/stores/counter.[js|ts]
檔案。
Pinia 商店範例
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('counter', {
state: () => ({
counter: 0,
}),
getters: {
doubleCount: (state) => state.counter * 2,
},
actions: {
increment() {
this.counter++;
},
},
})
我們已經建立了新的 Pinia 商店,但我們尚未在我們的應用程式中使用它。在 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 商店中存取路由器
只需在 Pinia 商店中使用 this.router
即可存取路由器。
這是一個範例
import { defineStore } from 'pinia'
export const useWhateverStore = defineStore('whatever', {
// ...
actions: {
whateverAction () {
this.router.push('...')
}
}
}