Pinia State Management
Pinia is Vue's official state management library. It gives you a central place to store data shared across multiple components, such as the current user, app configuration, notifications, or UI preferences.
If Vue's local state (ref, reactive) is enough for a single component, keep it local. Reach for Pinia when state needs to be reused, coordinated, or persisted across different parts of your app.
Why Use Pinia?
- Predictable state flow - One source of truth instead of duplicated state in many components
- Reusable logic - Keep business logic in stores instead of repeating it in UI components
- Great developer experience - TypeScript support, Vue Devtools integration, and simple API
Pinia in UserFrosting
In a standard UserFrosting frontend app, Pinia is already installed and wired in your app bootstrap. You can start creating stores right away.
UserFrosting also includes the Pinia persistence plugin. When a store enables persistence, its state is saved in browser storage and restored after a page reload.
You can create stores in app/assets/stores/. For example, let's create a simple counter store:
// app/assets/stores/counter.ts
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('counter', {
state: () => ({
count: 0,
}),
getters: {
doubleCount: (state) => state.count * 2,
},
actions: {
increment() {
this.count++
},
},
persist: true, // Enable persistence for this store
})
Use it in any component:
<script setup lang="ts">
import { useCounterStore } from '../stores/counter'
const counter = useCounterStore()
</script>
<template>
<button @click="counter.increment">Count: {{ counter.count }}</button>
<p>Double: {{ counter.doubleCount }}</p>
</template>
If you where to use the same counter in a second component, it would share the same state. Incrementing the counter in one component would update it in the other.
If persist: true is enabled on a Pinia store, the counter value is restored after refresh. This is different than a local component state (ref), where the value is recreated from scratch on each reload.