在深入研究核心概念之前,我們得知道 Store 是用 defineStore()
定義的,它的第一個(gè)參數(shù)要求是一個(gè)獨(dú)一無二的名字:
import { defineStore } from 'pinia'
// 你可以對(duì) `defineStore()` 的返回值進(jìn)行任意命名,但最好使用 store 的名字,同時(shí)以 `use` 開頭且以 `Store` 結(jié)尾。(比如 `useUserStore`,`useCartStore`,`useProductStore`)
// 第一個(gè)參數(shù)是你的應(yīng)用中 Store 的唯一 ID。
export const useAlertsStore = defineStore('alerts', {
// 其他配置...
})
這個(gè)名字 ,也被用作 id ,是必須傳入的, Pinia 將用它來連接 store 和 devtools。為了養(yǎng)成習(xí)慣性的用法,將返回的函數(shù)命名為 use... 是一個(gè)符合組合式函數(shù)風(fēng)格的約定。
defineStore()
的第二個(gè)參數(shù)可接受兩類值:Setup 函數(shù)或 Option 對(duì)象。
與 Vue 的選項(xiàng)式 API 類似,我們也可以傳入一個(gè)帶有 state
、actions
與 getters
屬性的 Option 對(duì)象
```js {2-10} export const useCounterStore = defineStore('counter', { state: () => ({ count: 0 }), getters: { double: (state) => state.count * 2, }, actions: { increment() { this.count++ }, }, })
你可以認(rèn)為 `state` 是 store 的數(shù)據(jù) (`data`),`getters` 是 store 的計(jì)算屬性 (`computed`),而 `actions` 則是方法 (`methods`)。
為方便上手使用,Option Store 應(yīng)盡可能直觀簡單。
## Setup Store
也存在另一種定義 store 的可用語法。與 Vue 組合式 API 的 [setup 函數(shù)](https://cn.vuejs.org/api/composition-api-setup.html) 相似,我們可以傳入一個(gè)函數(shù),該函數(shù)定義了一些響應(yīng)式屬性和方法,并且返回一個(gè)帶有我們想暴露出去的屬性和方法的對(duì)象。
```js
export const useCounterStore = defineStore('counter', () => {
const count = ref(0)
function increment() {
count.value++
}
return { count, increment }
})
在 Setup Store 中:
ref()
就是 state
屬性computed()
就是 getters
function()
就是 actions
Setup store 比 Option Store 帶來了更多的靈活性,因?yàn)槟憧梢栽谝粋€(gè) store 內(nèi)創(chuàng)建偵聽器,并自由地使用任何組合式函數(shù)。不過,請(qǐng)記住,使用組合式函數(shù)會(huì)讓 SSR 變得更加復(fù)雜。
和在 Vue 中如何選擇組合式 API 與選項(xiàng)式 API 一樣,選擇你覺得最舒服的那一個(gè)就好。如果你還不確定,可以先試試 Option Store。
雖然我們前面定義了一個(gè) store,但在我們使用 <script setup>
調(diào)用 useStore()
(或者使用 setup()
函數(shù),像所有的組件那樣) 之前,store 實(shí)例是不會(huì)被創(chuàng)建的:
<script setup>
import { useCounterStore } from '@/stores/counter'
// 可以在組件中的任意位置訪問 `store` 變量 ?
const store = useCounterStore()
</script>
你可以定義任意多的 store,但為了讓使用 pinia 的益處最大化(比如允許構(gòu)建工具自動(dòng)進(jìn)行代碼分割以及 TypeScript 推斷),你應(yīng)該在不同的文件中去定義 store。
如果你還不會(huì)使用 setup
組件,你也可以通過映射輔助函數(shù)來使用 Pinia。
一旦 store 被實(shí)例化,你可以直接訪問在 store 的 state
、getters
和 actions
中定義的任何屬性。我們將在后續(xù)章節(jié)繼續(xù)了解這些細(xì)節(jié),目前自動(dòng)補(bǔ)全將幫助你使用相關(guān)屬性。
請(qǐng)注意,store
是一個(gè)用 reactive
包裝的對(duì)象,這意味著不需要在 getters 后面寫 .value
,就像 setup
中的 props
一樣,如果你寫了,我們也不能解構(gòu)它:
<script setup>
const store = useCounterStore()
// ? 這將不起作用,因?yàn)樗茐牧隧憫?yīng)性
// 這就和直接解構(gòu) `props` 一樣
const { name, doubleCount } = store // [!code warning]
name // 將始終是 "Eduardo" // [!code warning]
doubleCount // 將始終是 0 // [!code warning]
setTimeout(() => {
store.increment()
}, 1000)
// ? 這樣寫是響應(yīng)式的
// ???? 當(dāng)然你也可以直接使用 `store.doubleCount`
const doubleValue = computed(() => store.doubleCount)
</script>
為了從 store 中提取屬性時(shí)保持其響應(yīng)性,你需要使用 storeToRefs()
。它將為每一個(gè)響應(yīng)式屬性創(chuàng)建引用。當(dāng)你只使用 store 的狀態(tài)而不調(diào)用任何 action 時(shí),它會(huì)非常有用。請(qǐng)注意,你可以直接從 store 中解構(gòu) action,因?yàn)樗鼈円脖唤壎ǖ?store 上:
<script setup>
import { storeToRefs } from 'pinia'
const store = useCounterStore()
// `name` 和 `doubleCount` 是響應(yīng)式的 ref
// 同時(shí)通過插件添加的屬性也會(huì)被提取為 ref
// 并且會(huì)跳過所有的 action 或非響應(yīng)式 (不是 ref 或 reactive) 的屬性
const { name, doubleCount } = storeToRefs(store)
// 作為 action 的 increment 可以直接解構(gòu)
const { increment } = store
</script>
更多建議: