Quasar предоставляет мощный каркас для создания современных веб-приложений на Vue.js, а Pinia выступает как современная альтернатива Vuex для управления состоянием. Интеграция Pinia в Quasar проект позволяет централизованно управлять данными, упрощает масштабирование приложения и обеспечивает типовую безопасность при работе с состоянием.
Для начала необходимо установить Pinia через npm или yarn:
npm install pinia
# или
yarn add pinia
После установки Pinia интегрируется в Quasar через основной файл
приложения, обычно src/main.js или
src/boot/pinia.js. Создание отдельного boot-файла позволяет
воспользоваться преимуществами Quasar Boot-процессов.
Пример подключения через boot-файл:
// src/boot/pinia.js
import { boot } from 'quasar/wrappers'
import { createPinia } from 'pinia'
export default boot(({ app }) => {
const pinia = createPinia()
app.use(pinia)
})
Необходимо убедиться, что boot-файл зарегистрирован в
quasar.conf.js:
boot: [
'pinia',
]
Это гарантирует, что Pinia будет доступна во всём приложении.
Хранилища Pinia (stores) представляют собой объекты, где хранится состояние, геттеры и методы для изменения данных.
Пример базового хранилища:
// src/stores/counter.js
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('counter', {
state: () => ({
count: 0
}),
getters: {
doubleCount: (state) => state.count * 2
},
actions: {
increment() {
this.count++
},
decrement() {
this.count--
}
}
})
Ключевые моменты:
state — функция, возвращающая объект состояния.getters — вычисляемые свойства, основанные на
состоянии.actions — методы для изменения состояния и выполнения
побочных эффектов.Использование хранилища в компонентах Quasar:
<template>
<q-page>
<q-btn @click="counter.increment" label="Increment" />
<q-btn @click="counter.decrement" label="Decrement" />
<div>Count: {{ counter.count }}</div>
<div>Double Count: {{ counter.doubleCount }}</div>
</q-page>
</template>
<script setup>
import { useCounterStore } from 'src/stores/counter'
const counter = useCounterStore()
</script>
Pinia поддерживает модульную структуру, что особенно полезно для крупных Quasar приложений. Каждый store можно организовать в отдельной папке, например:
src/stores/
auth.js
user.js
products.js
Это позволяет держать логику состояния изолированной и легко тестируемой. Также можно использовать Composition API внутри actions для сложных асинхронных операций:
// src/stores/user.js
import { defineStore } from 'pinia'
import axios from 'axios'
export const useUserStore = defineStore('user', {
state: () => ({
profile: null,
loading: false
}),
actions: {
async fetchProfile() {
this.loading = true
try {
const response = await axios.get('/api/user/profile')
this.profile = response.data
} finally {
this.loading = false
}
}
}
})
Quasar и Pinia полностью совместимы с TypeScript. Для типизации состояния создаются интерфейсы:
// src/stores/counter.ts
import { defineStore } from 'pinia'
interface CounterState {
count: number
}
export const useCounterStore = defineStore<'counter', CounterState>({
id: 'counter',
state: (): CounterState => ({
count: 0
}),
getters: {
doubleCount: (state) => state.count * 2
},
actions: {
increment() {
this.count++
}
}
})
Это обеспечивает автокомплит и строгую проверку типов в редакторах кода и во время компиляции.
Pinia легко интегрируется с компонентами Quasar, такими как
QDialog, QDrawer, QTable, где
состояние компонентов может храниться в централизованном store.
Например, управление открытием диалога через store:
// src/stores/ui.js
import { defineStore } from 'pinia'
export const useUiStore = defineStore('ui', {
state: () => ({
isDialogOpen: false
}),
actions: {
openDialog() {
this.isDialogOpen = true
},
closeDialog() {
this.isDialogOpen = false
}
}
})
<template>
<q-page>
<q-btn label="Open Dialog" @click="ui.openDialog" />
<q-dialog v-model="ui.isDialogOpen">
<q-card>
<q-card-section>
Контент диалога
</q-card-section>
<q-card-actions>
<q-btn flat label="Закрыть" @click="ui.closeDialog" />
</q-card-actions>
</q-card>
</q-dialog>
</q-page>
</template>
<script setup>
import { useUiStore } from 'src/stores/ui'
const ui = useUiStore()
</script>
Pinia поддерживает плагины для синхронизации состояния с
localStorage или sessionStorage, что позволяет
сохранять данные между перезагрузками страницы:
import { createPinia } from 'pinia'
import piniaPluginPersistedstate from 'pinia-plugin-persistedstate'
const pinia = createPinia()
pinia.use(piniaPluginPersistedstate)
Хранилище с сохранением состояния:
export const useCounterStore = defineStore('counter', {
state: () => ({ count: 0 }),
actions: { increment() { this.count++ } },
persist: true
})
Это обеспечивает автоматическую сериализацию и десериализацию состояния.
Pinia позволяет создавать асинхронные actions, что удобно для работы
с внешними API и интеграции с Quasar QSpinner,
QLinearProgress и другими компонентами для отображения
загрузки:
// src/stores/products.js
import { defineStore } from 'pinia'
import axios from 'axios'
export const useProductsStore = defineStore('products', {
state: () => ({
items: [],
loading: false
}),
actions: {
async fetchProducts() {
this.loading = true
try {
const response = await axios.get('/api/products')
this.items = response.data
} finally {
this.loading = false
}
}
}
})
Подключение к компонентам:
<q-page>
<q-linear-progress v-if="products.loading" indeterminate color="primary" />
<q-list>
<q-item v-for="item in products.items" :key="item.id">
<q-item-section>{{ item.name }}</q-item-section>
</q-item>
</q-list>
</q-page>
<script setup>
import { useProductsStore } from 'src/stores/products'
const products = useProductsStore()
products.fetchProducts()
</script>
auth,
ui, products.Эта архитектура обеспечивает чистую и масштабируемую структуру Quasar приложения с централизованным управлением состоянием через Pinia, упрощает тестирование и повышает предсказуемость поведения компонентов.