
Khi ứng dụng còn nhỏ, việc truyền dữ liệu qua props hay emit event giữa các component là đủ. Nhưng với ứng dụng lớn, dữ liệu phân tán khắp nơi → rất dễ rối. Lúc này ta cần một state management (quản lý dữ liệu tập trung).
Với Vue 2 thì thường dùng Vuex, còn Vue 3 thì Pinia là lựa chọn được khuyên dùng vì đơn giản và hiện đại hơn.
1. Cài đặt Pinia
Trong project Vue 3 (Vite), cài pinia:
npm install pinia
Trong main.js
đăng ký Pinia vào Vue app:
import { createApp } from 'vue' import { createPinia } from 'pinia' import App from './App.vue' const app = createApp(App) app.use(createPinia()) // đăng ký Pinia app.mount('#app')
2. Tạo Store đầu tiên
Trong thư mục src/stores/
, tạo file counter.js
:
import { defineStore } from 'pinia' export const useCounterStore = defineStore('counter', { state: () => ({ count: 0, }), getters: { double: (state) => state.count * 2, // giống computed }, actions: { increment() { this.count++ }, decrement() { this.count-- }, }, })
3. Sử dụng Store trong Component
Ví dụ trong App.vue
:
<template> <div class="app"> <h1>📊 Pinia Counter Example</h1> <p>Count: {{ counter.count }}</p> <p>Double: {{ counter.double }}</p> <button @click="counter.increment">➕ Tăng</button> <button @click="counter.decrement">➖ Giảm</button> </div> </template> <script setup> import { useCounterStore } from './stores/counter' const counter = useCounterStore() </script> <style> .app { font-family: sans-serif; text-align: center; margin-top: 50px; } button { margin: 5px; padding: 8px 16px; } </style>
👉 Ở đây counter
chính là store, có thể truy cập state (count
), getter (double
), và actions (increment
, decrement
).
4. Modular Store
Khi app lớn, ta có thể chia store ra thành nhiều module.
Ví dụ:
-
stores/counter.js
→ quản lý bộ đếm -
stores/user.js
→ quản lý thông tin user
user.js
:
import { defineStore } from 'pinia' export const useUserStore = defineStore('user', { state: () => ({ name: 'Thanh Nguyen', loggedIn: false, }), actions: { login(name) { this.name = name this.loggedIn = true }, logout() { this.name = '' this.loggedIn = false }, }, })
Trong App.vue
, dùng cả 2 store:
<template> <div> <h2>User: {{ user.loggedIn ? user.name : 'Guest' }}</h2> <button v-if="!user.loggedIn" @click="user.login('Nguyễn Bá Thành')">Login</button> <button v-else @click="user.logout">Logout</button> </div> </template> <script setup> import { useUserStore } from './stores/user' const user = useUserStore() </script>
5. Persist State (lưu vào localStorage)
Mặc định khi reload trang, store sẽ reset. Để giữ lại, ta có thể dùng plugin pinia-plugin-persistedstate:
npm install pinia-plugin-persistedstate
Trong main.js
:
import { createApp } from 'vue' import { createPinia } from 'pinia' import piniaPluginPersistedstate from 'pinia-plugin-persistedstate' import App from './App.vue' const pinia = createPinia() pinia.use(piniaPluginPersistedstate) const app = createApp(App) app.use(pinia) app.mount('#app')
Trong user.js
, bật persist:
export const useUserStore = defineStore('user', { state: () => ({ name: '', loggedIn: false, }), actions: { login(name) { this.name = name this.loggedIn = true }, logout() { this.name = '' this.loggedIn = false }, }, persist: true, // dữ liệu lưu vào localStorage })
👉 Giờ thì sau khi login, reload trang vẫn giữ được trạng thái.
🎯 Tổng kết
-
Pinia là state management chính thức cho Vue 3, thay thế Vuex.
-
Cấu trúc store có
state
,getter
,actions
. -
Có thể chia module cho app lớn.
-
Dùng plugin để persist state vào
localStorage
hoặcsessionStorage
.