Skip to content

Визначення сховища

Перш ніж заглибитися в основні концепції, вам потрібно знати, що сховище визначається за допомогою defineStore() і що воно вимагає унікального імені, яке передається в якості першого аргументу:

js
import { defineStore } from 'pinia'

// Ви можете назвати значення, що повертається функцією `defineStore()`, 
// як завгодно, але найкраще використовувати назву сховища, використовуючи 
// слова `use` та `Store` (наприклад, `useUserStore`, `useCartStore`, `useProductStore`).
// Перший аргумент - це унікальний ідентифікатор сховища у вашому додатку
export const useAlertsStore = defineStore('alerts', {
  // інші параметри...
})
import { defineStore } from 'pinia'

// Ви можете назвати значення, що повертається функцією `defineStore()`, 
// як завгодно, але найкраще використовувати назву сховища, використовуючи 
// слова `use` та `Store` (наприклад, `useUserStore`, `useCartStore`, `useProductStore`).
// Перший аргумент - це унікальний ідентифікатор сховища у вашому додатку
export const useAlertsStore = defineStore('alerts', {
  // інші параметри...
})

Це ім'я, що одночасно являється ідентифікатором, є обов'язковим і використовується в Pinia для приєднання сховища до інструментів розробника. Найменування функції, що повертається, use... є домовленістю між композиційними функціями, щоб зробити її використання зручним.

defineStore() приймає два різних значення для свого другого аргументу: функцію налаштувань або об'єкт опцій.

Опційні сховища

Подібно до опційного API Vue, ми також можемо передати об'єкт параметрів з властивостями стану, дій та гетерів

js
export const useCounterStore = defineStore('counter', {
  state: () => ({ count: 0, name: 'Дмитро' }),
  getters: {
    doubleCount: (state) => state.count * 2,
  },
  actions: {
    increment() {
      this.count++
    },
  },
})
export const useCounterStore = defineStore('counter', {
  state: () => ({ count: 0, name: 'Дмитро' }),
  getters: {
    doubleCount: (state) => state.count * 2,
  },
  actions: {
    increment() {
      this.count++
    },
  },
})

Ви можете думати про стан як про дані сховища, гетери як про обчислювані властивості сховища, а дії як про методи.

Опційні сховища повинні бути інтуїтивно зрозумілими та простими для початку роботи з ними.

Setup сховища

Існує також інший можливий синтаксис для визначення сховищ. Подібно до функції setup композиційного API Vue, ми можемо передати функцію, яка визначає реактивні властивості та методи й повертає об'єкт з властивостями та методами, які ми хочемо використовувати.

js
export const useCounterStore = defineStore('counter', () => {
  const count = ref(0)
  const name = ref('Дмитро')
  const doubleCount = computed(() => count.value * 2)
  function increment() {
    count.value++
  }

  return { count, name, doubleCount, increment }
})
export const useCounterStore = defineStore('counter', () => {
  const count = ref(0)
  const name = ref('Дмитро')
  const doubleCount = computed(() => count.value * 2)
  function increment() {
    count.value++
  }

  return { count, name, doubleCount, increment }
})

У setup сховищах:

  • ref() стають властивостями стану
  • computed() стають гетерами
  • function() стають діями

Зауважте, що ви повинні повернути всі властивості стану у Setup сховищах для Pinia, щоб отримати їх як стан. Іншими словами, ви не можете мати приватні властивості стану у сховищах.

Setup сховища забезпечують набагато більшу гнучкість, ніж Опційні сховища, оскільки ви можете створювати спостерігачі у межах сховища і вільно використовувати будь-які композиційні функції. Однак майте на увазі, що використання композиційних функцій ускладниться при використанні SSR.

Setup сховища також можуть покладатися на глобальні надані властивості, такі як Router або Route. Будь-яку властивість надану на рівні застосунку можна отримати зі сховища за допомогою inject(), як і в компонентах:

ts
import { inject } from 'vue'
import { useRoute } from 'vue-router'

export const useSearchFilters = defineStore('search-filters', () => {
  const route = useRoute()
  // це припускає, що було викликано `app.provide('appProvided', 'value')`
  const appProvided = inject('appProvided')

  // ...

  return {
    // ...
  }
})
import { inject } from 'vue'
import { useRoute } from 'vue-router'

export const useSearchFilters = defineStore('search-filters', () => {
  const route = useRoute()
  // це припускає, що було викликано `app.provide('appProvided', 'value')`
  const appProvided = inject('appProvided')

  // ...

  return {
    // ...
  }
})

WARNING

Не повертайте такі властивості, як useRoute() або appProvided (з прикладу вище), оскільки вони не належать до самого сховища, і ви можете отримати до них прямий доступ у компонентах за допомогою useRoute() та inject('appProvided').

Який синтаксис вибрати?

Як і у випадку з композиційним та опційним API у Vue, виберіть той, з яким ви почуваєтесь найбільш комфортно. Якщо ви не впевнені, спершу спробуйте опційне сховище.

Використання сховища

Ми визначаємо сховище, тому що воно не буде створено до моменту, поки use...Store() буде викликано в компоненті <script setup> (або в setup(), як і для всіх композиційних функцій):

vue
<script setup>
import { useCounterStore } from '@/stores/counter'

// отримати доступ до змінної `store` в будь-якому місці компонента ✨
const store = useCounterStore()
</script>
<script setup>
import { useCounterStore } from '@/stores/counter'

// отримати доступ до змінної `store` в будь-якому місці компонента ✨
const store = useCounterStore()
</script>

ПОРАДА

Якщо ви ще не використовуєте setup хук в компонентах, ви можете використовувати Pinia з допоміжними функціями зіставлення.

Ви можете визначити стільки сховищ, скільки хочете, і ви повинні визначити кожне сховище в окремому файлі, щоб отримати максимальну користь від Pinia (наприклад, автоматично дозволити вашому пакувальнику розбивати код і надавати визначення типів в TypeScript).

Щойно сховище створено, ви можете отримати доступ до будь-яких властивостей, визначених у state, getters та actions безпосередньо у сховищі. Ми розглянемо їх детально на наступних сторінках, але автодоповнення допоможе вам у цьому.

Зверніть увагу, що сховище є реактивним об'єктом, тобто нема потреби писати .value після гетерів, але, як і реквізити в хуку setup, ми не можемо його деструктурувати:

vue
<script setup>
import { useCounterStore } from '@/stores/counter'
const store = useCounterStore()
// ❌ Це не спрацює, оскільки порушує реактивність
// це те ж саме, що і деструктуризація з `реквізитів`
const { name, doubleCount } = store 
name // завжди буде "Дмитро" 
doubleCount // завжди буде 0 

setTimeout(() => {
  store.increment()
}, 1000)

// ✅ ця змінна буде реактивною
// 💡 але ви також можете використовувати `store.doubleCount` напряму
const doubleValue = computed(() => store.doubleCount)
</script>
<script setup>
import { useCounterStore } from '@/stores/counter'
const store = useCounterStore()
// ❌ Це не спрацює, оскільки порушує реактивність
// це те ж саме, що і деструктуризація з `реквізитів`
const { name, doubleCount } = store 
name // завжди буде "Дмитро" 
doubleCount // завжди буде 0 

setTimeout(() => {
  store.increment()
}, 1000)

// ✅ ця змінна буде реактивною
// 💡 але ви також можете використовувати `store.doubleCount` напряму
const doubleValue = computed(() => store.doubleCount)
</script>

Деструктурування з Store

Щоб витягти властивості зі сховища, зберігши його реактивність, вам потрібно використовувати storeToRefs(). Він створить посилання для кожної реактивної властивості. Це корисно, коли ви використовуєте лише стан зі сховища, але не викликаєте жодної дії. Зверніть увагу, що ви можете деструктурувати дії безпосередньо зі сховища, оскільки вони також прив'язані до самого сховища:

vue
<script setup>
import { useCounterStore } from '@/stores/counter'
import { storeToRefs } from 'pinia'

const store = useCounterStore()
// `name` та `doubleCount` є реактивними посиланнями
// Це також витягне посилання на властивості, додані плагінами,
// але пропустить будь-яку дію або нереактивну властивість
const { name, doubleCount } = storeToRefs(store)
// дію increment можна просто деструктурувати
const { increment } = store
</script>
<script setup>
import { useCounterStore } from '@/stores/counter'
import { storeToRefs } from 'pinia'

const store = useCounterStore()
// `name` та `doubleCount` є реактивними посиланнями
// Це також витягне посилання на властивості, додані плагінами,
// але пропустить будь-яку дію або нереактивну властивість
const { name, doubleCount } = storeToRefs(store)
// дію increment можна просто деструктурувати
const { increment } = store
</script>

Released under the MIT License.