В Quasar, как и в любом приложении на Vue.js, управление состоянием играет ключевую роль в построении масштабируемого и поддерживаемого кода. Stores обеспечивают централизованное хранение данных, их реактивность и удобное взаимодействие между компонентами.
Quasar использует Pinia в качестве рекомендуемого менеджера состояния. Store — это модуль, содержащий:
Структура типичного store выглядит следующим образом:
import { defineStore } from 'pinia';
export const useUserStore = defineStore('user', {
state: () => ({
id: null,
name: '',
email: ''
}),
getters: {
isLoggedIn: (state) => !!state.id
},
actions: {
setUser(user) {
this.id = user.id;
this.name = user.name;
this.email = user.email;
},
logout() {
this.id = null;
this.name = '';
this.email = '';
}
}
});
State создаётся как функция, возвращающая объект. Важные аспекты:
Пример сложного state:
state: () => ({
cart: [],
filters: {
category: 'all',
priceRange: [0, 100]
}
})
Изменение cart лучше делать через
actions, чтобы сохранить предсказуемость изменений.
Getters позволяют создавать вычисляемые свойства, которые зависят от state. Они используются для:
Пример getter с фильтрацией:
getters: {
filteredProducts: (state) => (category) => {
return state.products.filter(p => p.category === category);
},
cartTotal: (state) => {
return state.cart.reduce((sum, item) => sum + item.price * item.quantity, 0);
}
}
Геттеры автоматически кешируются и пересчитываются только при изменении зависимостей.
Actions позволяют изменять state и выполнять асинхронные операции:
this.Пример асинхронного запроса:
actions: {
async fetchUser(userId) {
try {
const response = await fetch(`/api/users/${userId}`);
const data = await response.json();
this.setUser(data);
} catch (error) {
console.error('Ошибка загрузки пользователя:', error);
}
}
}
Для крупных приложений рекомендуется создавать несколько независимых stores, каждый из которых отвечает за отдельную область:
userStore — данные о пользователе и аутентификацииcartStore — корзина и покупкиproductStore — каталог товаров и фильтрыStores можно комбинировать в компонентах:
import { useUserStore } from 'stores/userStore';
import { useCartStore } from 'stores/cartStore';
const userStore = useUserStore();
const cartStore = useCartStore();
console.log(userStore.isLoggedIn);
console.log(cartStore.cartTotal);
Quasar обеспечивает прямую интеграцию Pinia, что позволяет легко использовать store в компонентах:
<template>
<div>
<h2>Добро пожаловать, {{ userStore.name }}</h2>
<p>Товаров в корзине: {{ cartStore.cart.length }}</p>
</div>
</template>
<script setup>
import { useUserStore } from 'stores/userStore';
import { useCartStore } from 'stores/cartStore';
const userStore = useUserStore();
const cartStore = useCartStore();
</script>
Преимущества такого подхода:
Pinia обеспечивает полную реактивность:
computed с getters позволяет создавать
цепочки реактивных зависимостей.Пример реактивного наблюдения:
import { watch } from 'vue';
watch(
() => userStore.isLoggedIn,
(newValue) => {
console.log('Статус входа изменился:', newValue);
}
);
Для длительного хранения данных между перезагрузками можно использовать plugins Pinia:
import { createPinia } from 'pinia';
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate';
const pinia = createPinia();
pinia.use(piniaPluginPersistedstate);
Пример сохранения корзины:
export const useCartStore = defineStore('cart', {
state: () => ({ cart: [] }),
actions: {
addToCart(item) {
this.cart.push(item);
}
},
persist: true
});
Пример типизации state:
interface UserState {
id: number | null;
name: string;
email: string;
}
export const useUserStore = defineStore<'user', UserState>({
state: (): UserState => ({
id: null,
name: '',
email: ''
})
});
Эта структура позволяет строить масштабируемые, реактивные и предсказуемые приложения, полностью используя возможности Quasar и Pinia для управления состоянием.