Управление состоянием: Pinia

Когда состояние нужно многим компонентам сразу, его выносят в общее хранилище. Знакомимся с официальным решением — Pinia.

Pinia — официальная библиотека управления состоянием для Vue. Она хранит данные в store — общем месте, доступном из любого компонента приложения.

Зачем нужен общий store

Пропсы и события хороши для соседних компонентов. Но «корзина», «текущий пользователь» или «тема» нужны во многих местах сразу, на разных ветках дерева. Передавать их пропсами через всё дерево мучительно. Store — единый источник правды: любой компонент читает и меняет его напрямую.

Анатомия store

Store описывают функцией defineStore. В ней три части: state (данные), getters (производные значения, как computed) и actions (методы, меняющие state):

import { defineStore } from 'pinia'

export const useCartStore = defineStore('cart', {
  state: () => ({ items: [] }),
  getters: {
    count: (state) => state.items.length,
    total: (state) => state.items.reduce((sum, i) => sum + i.price, 0),
  },
  actions: {
    add(item) { this.items.push(item) },
    clear() { this.items = [] },
  },
})

Использование в компоненте

Компонент вызывает store-хук и работает с ним напрямую — реактивно:

<template>
  <p>Товаров: {{ cart.count }} на {{ cart.total }} ₽</p>
  <button @click="cart.add({ name: 'Кофе', price: 200 })">Добавить</button>
</template>

<script setup>
import { useCartStore } from './stores/cart'
const cart = useCartStore()
</script>

Любой другой компонент, вызвавший useCartStore(), увидит те же данные — они общие. Это и отличает store от состояния внутри одного компонента.

Промоделируем store на JS

По сути store — это объект с данными, производными значениями и методами. Соберём упрощённую корзину:

function createCartStore() {
  const state = { items: [] };
  return {
    add(item) { state.items.push(item); },
    get count() { return state.items.length; },
    get total() { return state.items.reduce((s, i) => s + i.price, 0); },
  };
}

const cart = createCartStore();
cart.add({ name: "Кофе", price: 200 });
cart.add({ name: "Чай", price: 150 });

console.log("Товаров:", cart.count);
console.log("Сумма:", cart.total);

Вывод:

Товаров: 2
Сумма: 350

Части store

ЧастьАналог в компонентеНазначение
staterefсами данные
getterscomputedпроизводные значения
actionsметодыизменение state

Итог

  • Pinia — официальное хранилище общего состояния приложения.
  • Store описывают defineStore: state, getters, actions.
  • Любой компонент через useStore() читает и меняет одни и те же данные.
  • state похож на ref, getters — на computed, actions — на методы.
Проверьте себя
1. Какую задачу решает Pinia?
AМаршрутизацию между страницами
BХранение общего состояния приложения, доступного из любого компонента
CЗагрузку данных с сервера
DАнимацию переходов
2. Чему в обычном компоненте соответствуют getters в store Pinia?
Aметодам (actions)
Bвычисляемым свойствам computed — это производные значения
Cпропсам
Dхукам жизненного цикла
3. Что увидят два разных компонента, вызвавшие один и тот же useCartStore()?
AКаждый получит свою независимую копию данных
BОдни и те же общие данные — store един для всего приложения
CОшибку повторного вызова
DПустой store во втором случае
Поддержать проект