patternjavascriptvueModerate
Pinia store patterns — defining and using stores in Vue 3
Viewed 0 times
Pinia 2.x, Vue 3.2+
piniastorestoreToRefsdefineStorevue3 state managementsetup store
Error Messages
Problem
Vuex patterns don't map cleanly to Vue 3. Developers copy Vuex's mutations/actions pattern into Pinia, missing simpler Composition API patterns. Stores are also used outside components incorrectly.
Solution
Use Pinia's Setup Store syntax for flexibility, or Options Store for simplicity:
// stores/user.ts
import { defineStore } from 'pinia';
import { ref, computed } from 'vue';
// Setup Store (Composition API style — recommended)
export const useUserStore = defineStore('user', () => {
const user = ref<User | null>(null);
const isLoggedIn = computed(() => user.value !== null);
async function login(credentials: Credentials) {
user.value = await authApi.login(credentials);
}
function logout() {
user.value = null;
}
return { user, isLoggedIn, login, logout };
});
// In a component
<script setup lang="ts">
import { useUserStore } from '@/stores/user';
const userStore = useUserStore();
// Destructure with storeToRefs to keep reactivity
import { storeToRefs } from 'pinia';
const { user, isLoggedIn } = storeToRefs(userStore);
// Actions can be destructured normally
const { login, logout } = userStore;
</script>
// stores/user.ts
import { defineStore } from 'pinia';
import { ref, computed } from 'vue';
// Setup Store (Composition API style — recommended)
export const useUserStore = defineStore('user', () => {
const user = ref<User | null>(null);
const isLoggedIn = computed(() => user.value !== null);
async function login(credentials: Credentials) {
user.value = await authApi.login(credentials);
}
function logout() {
user.value = null;
}
return { user, isLoggedIn, login, logout };
});
// In a component
<script setup lang="ts">
import { useUserStore } from '@/stores/user';
const userStore = useUserStore();
// Destructure with storeToRefs to keep reactivity
import { storeToRefs } from 'pinia';
const { user, isLoggedIn } = storeToRefs(userStore);
// Actions can be destructured normally
const { login, logout } = userStore;
</script>
Why
Pinia has no mutations — state can be modified directly in actions or with $patch(). The Setup Store syntax mirrors the Composition API, making it intuitive for Vue 3 developers. storeToRefs() is essential for destructuring reactive state without losing reactivity.
Gotchas
- Destructuring store state without storeToRefs() loses reactivity — user becomes a plain value
- Never call useUserStore() outside a component/pinia context before the app is mounted
- Use store.$patch({ field: value }) for partial updates to avoid losing other state
- Pinia stores persist between hot reloads in dev — use store.$reset() in the setup store by returning it
Code Snippets
Pinia $patch and $subscribe
// Partial update
userStore.$patch({ name: 'Alice', age: 30 });
// Subscribe to store changes
userStore.$subscribe((mutation, state) => {
localStorage.setItem('user', JSON.stringify(state.user));
});Context
When managing shared state with Pinia in Vue 3 applications
Revisions (0)
No revisions yet.