YouTip LogoYouTip

Vue3 Pinia

In Vue3, state management is an unavoidable topic. Pinia is a lightweight state management library for Vue.js that allows you to share and manage state between components. We can think of Pinia as a global data warehouse where all components can retrieve or update data. This chapter introduces Pinia, the officially recommended state management library for Vue3. Compared to Vuex, Pinia provides a more concise state management solution that aligns with the Vue3 Composition API mindset. The following diagram compares the structural differences between the two: * Vuex uses a tree structure with a single store and multi-level modules, with fixed hierarchy, relying on mutations, and is overall heavier. * Pinia consists of multiple independent stores, is flat, lightweight, without modules, and has no namespace burden. !(#) **Pinia Core Features:** * Supports Vue2 and Vue3 * Minimal API design * Full TypeScript support * Supports Composition API * Modular design without nested modules Pinia's flat structure allows components to directly connect to any store, getting what they need without going through tree-like modules or namespace paths. State flow is simple, direct, and has low coupling. !(#) * * * ## Installation and Configuration Create a project with Vite: npm create vite@latest vue-pinia-demo --template vue cd vue-pinia-demo npm install ### Install Pinia First, install Pinia in your Vue3 project: npm install pinia # or yarn add pinia Pinia has three parts: * state: stores data * getters: computes derived data * actions: executes logic, modifies state ### Configure Pinia Configure Pinia in src/main.js or src/main.ts: ## Example // main.js import{ createApp } from 'vue' import{ createPinia } from 'pinia' import App from './App.vue' // Create Pinia instance const pinia = createPinia() // Create Vue app const app = createApp(App) // Use Pinia app.use(pinia) app.mount('#app') * * * ## Creating the First Store A Store is the data warehouse in Pinia. Let's create a simple counter Store. ### Define Store Create src/stores/useCounter.js: ## Example // stores/useCounter.js import{ defineStore } from 'pinia' // Use defineStore to define store // First parameter is the unique ID of the store // Second parameter is the store's configuration options export const useCounterStore = defineStore('counter',{ // state: defines the store's state data state:()=>({ count:0, name:'My Counter' }), // getters: defines computed properties based on state getters:{ doubleCount:(state)=> state.count*2, // Use this to access other getters doubleCountPlusOne(){ return this.doubleCount+1 } }, // actions: defines methods to modify state actions:{ increment(){ this.count++ }, decrement(){ this.count-- }, // Can receive parameters incrementBy(amount){ this.count+= amount }, // Async action async incrementAsync(){ // Simulate async operation await new Promise(resolve => setTimeout(resolve,1000)) this.count++ } } }) ### Store Structure Explanation Let's understand the parts of a Store through a table: | Part | Function | Example | | --- | --- | --- | | **state** | Defines stored data | `count: 0` | | **getters** | Computed properties based on state | `doubleCount: state => state.count * 2` | | **actions** | Methods to modify state | `increment() { this.count++ }` | * * * ## Using Store in Components ### Basic Usage The component code for src/components/CounterComponent.vue is as follows: ## Example

{{ store.name }}

Current count: {{ store.count }}

Double count: {{ store.doubleCount }}

Double plus one: {{ store.doubleCountPlusOne }}

import { useCounterStore } from '../stores/useCounter' // Use store in setup const store = useCounterStore() // Method to reset state function reset() { store.$reset() // $reset method can reset state to initial value } Modify src/App.vue code as follows: ## Example import CounterComponent from './components/CounterComponent.vue' The entire project structure: !(#) Execute the npm run dev command, and visit **http://localhost:5173/** in the browser to see the effect: !(#) ### Reactive Destructuring If you want to directly use state properties in the template, you can use `storeToRefs`: ## Example

Count: {{ count }}

Name: {{ name }}

import { storeToRefs } from 'pinia' import { useCounterStore } from '@/stores/counter' const store = useCounterStore() // Use storeToRefs to maintain reactivity const { count, name } = storeToRefs(store) // Note: Direct destructuring will lose reactivity! // Wrong way: const { count, name } = store * * * ## Composition API Style Store Pinia also supports defining Stores using the Composition API style: ## Example // stores/user.js import{ defineStore } from 'pinia' import{ ref, computed } from 'vue' export const useUserStore = defineStore('user',()=>{ // state const user = ref(null) const isLoggedIn = ref(false) // getters const userName = computed(()=> user.value?.name||'Guest') const userAge = computed(()=> user.value?.age||0) // actions function login(userData){ user.value= userData isLoggedIn.value=true } function logout(){ user.value=null isLoggedIn.value=false } return{ user, isLoggedIn, userName, userAge, login, logout } }) * * * ## Store Interaction Multiple Stores can call each other: ## Example // stores/cart.js import{ defineStore } from 'pinia' export const useCartStore = defineStore('cart',{ state:()=>({ items:[] }), actions:{ addItem(product){ this.items.push(product) // Call other store's action const userStore = useUserStore() if(userStore.isLoggedIn){ // Sync to user cart this.syncToUserCart() } } } }) * * * ## Practical Example: Shopping Cart Let's create a complete shopping cart example: ## Example // stores/products.js export const useProductStore = defineStore('products',{ state:()=>({ products:[ { id:1, name:'Laptop', price:5999, stock:10}, { id:2, name:'Smartphone', price:3999, stock:20}, { id:3, name:'Wireless Earphones', price:299, stock:50} ] }), getters:{ // Get product by ID getProductById:(state)=>(id)=>{ return state.products.find(product => product.id=== id) }, // Get products in stock availableProducts:(state)=>{ return state.products.filter(product => product.stock>0) } } }) ## Example // stores/cart.js export const useCartStore = defineStore('cart',{ state:()=>({ items:[],// { productId, quantity } discount:0 }), getters:{ // Total number of items in cart totalItems:(state)=>{ return state.items.reduce((total, item)=> total + item.quantity,0) }, // Total amount in cart totalPrice:(state)=>{ const productStore = useProductStore() return state.items.reduce((total, item)=>{ const product = productStore.getProductById(item.productId) return total +(product?.price||0)* item.quantity },0) }, // Final price after discount finalPrice:(state)=>{ return state.totalPrice*(1- state.discount/100) } }, actions:{ // Add product to cart addToCart(productId, quantity =1){ const existingItem =this.items.find(item => item.productId=== productId) if(existingItem){ existingItem.quantity+= quantity }else{ this.items.push({ productId, quantity }) } }, // Remove product from cart removeFromCart(productId){ this.items=this.items.filter(item => item.productId!== productId) }, // Clear cart clearCart(){ this.items=[] this.discount=0 }, // Set discount setDiscount(percent){ this.discount=Math.max(0,Math.min(100, percent)) } } }) ### Using Shopping Cart in Components ## Example

Shopping Cart ({{ cart.totalItems }} items)

Cart is empty

{{ item.product.name }} Β₯{{ item.product.price }} Quantity: {{ item.quantity }} Subtotal: Β₯{{ item.product.price * item.quantity }}

Total: Β₯{{ cart.totalPrice }}

0">Discount: {{ cart.discount }}%

Pay: Β₯{{ cart.finalPrice }}

import { computed } from 'vue' import { useCartStore } from '@/stores/cart' import { useProductStore } from '@/stores/products' const cart = useCartStore() const products = useProductStore() // Calculate cart item details const cartItems = computed(() => { return cart.items.map(item => ({ product: products.getProductById(item.productId), quantity: item.quantity })).filter(item => item.product) // Filter out non-existent products }) * * * ## Best Practices and Notes ### 1. Store Naming Convention ## Example // Good naming export const useUserStore = def...
← Ai Agent IntroPython Memento β†’