A Pinia store helps you keep and manage data in one place for your Vue app. It makes sharing data easy and organized.
Creating a Pinia store in Vue
Introduction
Syntax
Vue
import { defineStore } from 'pinia' export const useStore = defineStore('storeId', { state: () => ({ // your data here }), getters: { // computed properties here }, actions: { // functions to change state here } })
defineStore creates a store with a unique ID.
state is a function returning an object holding your data.
Examples
Vue
import { defineStore } from 'pinia' export const useCounterStore = defineStore('counter', { state: () => ({ count: 0 }), actions: { increment() { this.count++ } } })
Vue
import { defineStore } from 'pinia' export const useUserStore = defineStore('user', { state: () => ({ name: '', loggedIn: false }), getters: { welcomeMessage: (state) => `Hello, ${state.name}` }, actions: { login(name) { this.name = name this.loggedIn = true } } })
Sample Program
This example shows a simple todo list using a Pinia store. You can add todos and toggle their done status. The store keeps the list and updates it for the app.
Vue
import { createApp, ref } from 'vue' import { createPinia, defineStore } from 'pinia' // Create a store export const useTodoStore = defineStore('todo', { state: () => ({ todos: [] }), actions: { addTodo(text) { this.todos.push({ text, done: false }) }, toggleTodo(index) { this.todos[index].done = !this.todos[index].done } } }) // Vue app component const App = { template: ` <div> <h1>Todo List</h1> <input v-model="newTodo" @keyup.enter="add" placeholder="Add todo" aria-label="Add todo" /> <ul> <li v-for="(todo, i) in todoStore.todos" :key="i"> <label> <input type="checkbox" v-model="todo.done" /> <span :style="{ textDecoration: todo.done ? 'line-through' : 'none' }">{{ todo.text }}</span> </label> </li> </ul> </div> `, setup() { const todoStore = useTodoStore() const newTodo = ref('') function add() { if (newTodo.value.trim()) { todoStore.addTodo(newTodo.value.trim()) newTodo.value = '' } } return { todoStore, newTodo, add } } } // Create app and use Pinia const app = createApp(App) const pinia = createPinia() app.use(pinia) app.mount('#app')
Important Notes
Always give your store a unique ID string in defineStore.
Use actions to change state safely and keep code organized.
Pinia works well with Vue 3 and Composition API for clean code.
Summary
Pinia stores hold shared data for Vue apps.
Define state, getters, and actions inside defineStore.
Use stores to keep your app data organized and easy to update.
Practice
1. What is the main purpose of creating a Pinia store in a Vue application?
easy
Solution
Step 1: Understand what Pinia stores do
Pinia stores are designed to hold shared data (state) that multiple components can access and update.Step 2: Identify the correct purpose
Styling, routing, and HTML templates are handled by other parts of Vue or related libraries, not Pinia stores.Final Answer:
To hold and manage shared state across components -> Option CQuick Check:
Pinia stores = shared state management [OK]
Hint: Pinia stores manage shared data, not styles or routes [OK]
Common Mistakes:
- Confusing Pinia with CSS or routing libraries
- Thinking Pinia handles templates
- Assuming Pinia is for styling
2. Which of the following is the correct way to define a Pinia store named 'user' using
defineStore?easy
Solution
Step 1: Recall the correct syntax for defineStore
The correct syntax is defineStore('storeId', { state: () => ({ ... }) }) and assign it to a function named useStoreId.Step 2: Check each option
const useUserStore = defineStore('user', { state: () => ({ name: '' }) }) uses defineStore with correct parameters and naming. const userStore = createStore('user', { state: () => ({ name: '' }) }) uses createStore which is incorrect. const useUserStore = defineStore({ name: 'user', state: () => ({ name: '' }) }) passes an object without storeId string first. const userStore = defineStore('user', { data: () => ({ name: '' }) }) uses 'data' instead of 'state'.Final Answer:
const useUserStore = defineStore('user', { state: () => ({ name: '' }) }) -> Option DQuick Check:
defineStore('id', { state }) syntax = const useUserStore = defineStore('user', { state: () => ({ name: '' }) }) [OK]
Hint: Use defineStore('id', { state: () => ({}) }) with useId naming [OK]
Common Mistakes:
- Using createStore instead of defineStore
- Passing object without store id string
- Using 'data' instead of 'state' key
3. Given this Pinia store definition:
What will be the value of
const useCounterStore = defineStore('counter', {
state: () => ({ count: 0 }),
actions: {
increment() { this.count++ }
}
})What will be the value of
count after calling increment() twice?medium
Solution
Step 1: Understand initial state and action
The initial count is 0. The increment action increases count by 1 each time it is called.Step 2: Calculate count after two increments
Calling increment() twice adds 1 + 1 to count, so count becomes 2.Final Answer:
2 -> Option BQuick Check:
0 + 1 + 1 = 2 [OK]
Hint: Each increment adds 1; two calls add 2 total [OK]
Common Mistakes:
- Forgetting to call increment twice
- Assuming count resets each call
- Confusing initial value with updated value
4. Identify the error in this Pinia store code:
const useTodoStore = defineStore('todo', {
state: () => ({ todos: [] }),
actions: {
addTodo(todo) {
this.todos.push(todo)
}
}
})
// Usage
const todoStore = useTodoStore()
todoStore.addTodo('Learn Pinia')medium
Solution
Step 1: Check the store definition syntax
The store is correctly defined with state as a function returning an object, and actions modifying state properly.Step 2: Identify missing parts
The code snippet does not show importing defineStore from 'pinia', which is required to use defineStore.Final Answer:
Missing import of defineStore from 'pinia' -> Option AQuick Check:
Always import defineStore before use [OK]
Hint: Always import defineStore from 'pinia' before defining stores [OK]
Common Mistakes:
- Forgetting to import defineStore
- Thinking state must be an object, not a function
- Believing actions cannot modify state
5. You want to create a Pinia store that keeps track of a user's profile with a name and age, and includes a getter to check if the user is an adult (age >= 18). Which of the following is the correct way to define this store?
hard
Solution
Step 1: Check state definition
State must be a function returning an object. Options C and D do this correctly; A and B do not.Step 2: Check getter syntax
Getters can be defined as functions using 'this' to access state. const useUserStore = defineStore('user', { state: () => ({ name: '', age: 0 }), getters: { isAdult() { return this.age >= 18 } } }) uses this correctly. const useUserStore = defineStore('user', { state: { name: '', age: 0 }, getters: { isAdult: (state) => state.age >= 18 } }) has incorrect state. const useUserStore = defineStore('user', { state: { name: '', age: 0 }, getters: { isAdult() { return this.age >= 18 } } }) has incorrect state. const useUserStore = defineStore('user', { state: () => ({ name: '', age: 0 }), actions: { isAdult() { return this.age >= 18 } } }) puts isAdult in actions, which is wrong because isAdult is a computed property, not an action.Final Answer:
const useUserStore = defineStore('user', { state: () => ({ name: '', age: 0 }), getters: { isAdult() { return this.age >= 18 } } }) -> Option AQuick Check:
State as function + getter with this = const useUserStore = defineStore('user', { state: () => ({ name: '', age: 0 }), getters: { isAdult() { return this.age >= 18 } } }) [OK]
Hint: State is function; getters use this for reactive access [OK]
Common Mistakes:
- Defining state as object instead of function
- Putting computed logic inside actions
- Using arrow function getters with state parameter incorrectly
Recommended
Ready to prove it?
Pass the test and this pattern moves unknown
10 questions ~5 mineasy hard
