State Management
This document details the Pinia state management solution used in the Antdv Next Admin project, including the role of each Store, usage methods, and best practices.
Table of Contents
- Pinia Basics
- Auth Store
- Permission Store
- Theme Store
- Tabs Store
- Layout Store
- Other Stores
- Store Composition
- Best Practices
Pinia Basics
The project uses Pinia's Setup Store syntax, which is a state management approach in Vue 3 Composition API style.
Setup Store Pattern
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'
// Define Store
export const useExampleStore = defineStore('example', () => {
// State: define state using ref
const count = ref(0)
const user = ref<User | null>(null)
// Getters: define computed properties using computed
const doubleCount = computed(() => count.value * 2)
const isLoggedIn = computed(() => !!user.value)
// Actions: define methods using regular functions
const increment = () => {
count.value++
}
const setUser = (userData: User) => {
user.value = userData
}
// Must return all content to be exposed
return {
count,
user,
doubleCount,
isLoggedIn,
increment,
setUser,
}
})Using Stores
<script setup lang="ts">
import { useExampleStore } from '@/stores/example'
import { storeToRefs } from 'pinia'
// Get Store instance
const exampleStore = useExampleStore()
// Use storeToRefs to destructure while maintaining reactivity
const { count, doubleCount } = storeToRefs(exampleStore)
// Directly destructure methods
const { increment } = exampleStore
</script>Auth Store
Manages user authentication information, including login status, tokens, and user information.
Location
src/stores/auth.ts
State
const token = ref<string | null>(localStorage.getItem(TOKEN_KEY))
const refreshTokenValue = ref<string | null>(localStorage.getItem(REFRESH_TOKEN_KEY))
const user = ref<User | null>(null)
const roles = ref<Role[]>([])
const permissions = ref<Permission[]>([])Getters
// Is logged in
const isLoggedIn = computed(() => !!token.value && !!user.value)
// User role list (string array)
const userRoles = computed(() => roles.value.map(role => role.code))
// User permission list (string array)
const userPermissions = computed(() => permissions.value.map(perm => perm.code))Actions
Login
// Login (automatically detects Demo/production mode)
await authStore.login(username, password)
// After successful login, automatically:
// 1. Save token to localStorage
// 2. Get user information
// 3. Update roles and permissionsLogout
// Clear all authentication information
authStore.logout()
// Automatically clears:
// 1. Token and RefreshToken
// 2. User information
// 3. Data in localStoragePermission Check
// Check if has a role
const hasRole = (role: string): boolean
// Check if has any role
const hasAnyRole = (roleList: string[]): boolean
// Check if has all roles
const hasAllRoles = (roleList: string[]): boolean
// Check if has a permission
const hasPermission = (permission: string): boolean
// Check if has any permission
const hasAnyPermission = (permissionList: string[]): boolean
// Check if has all permissions
const hasAllPermissions = (permissionList: string[]): booleanPermission Store
Manages route permissions and dynamic menu generation.
Location
src/stores/permission.ts
Actions
Generate Routes
// Generate accessible routes based on user permissions
await permissionStore.generateRoutes()
// Internal logic:
// 1. Get user permissions
// 2. Filter asyncRoutes
// 3. Generate menu tree
// 4. Add to routerTheme Store
Manages application theme, including light/dark mode, theme colors, CSS variables, etc.
Location
src/stores/theme.ts
State
const themeMode = ref<ThemeMode>('light')
const primaryColor = ref<string>('#1677ff')
const sidebarTheme = ref<'light' | 'dark'>('dark')Actions
// Set theme mode
themeStore.setThemeMode('dark') // Dark
themeStore.setThemeMode('light') // Light
themeStore.setThemeMode('auto') // Follow system
// Set theme color
themeStore.setPrimaryColor('#1677ff')
// Set sidebar theme
themeStore.setSidebarTheme('dark')
themeStore.setSidebarTheme('light')Tabs Store
Manages multi-tab navigation, including tab list, caching, and context menu.
Location
src/stores/tabs.ts
Actions
// Add tab
tabsStore.addTab({
path: '/dashboard',
title: 'Dashboard',
name: 'Dashboard',
keepAlive: true,
affix: false,
})
// Close tab
tabsStore.closeTab('/dashboard')
// Close other tabs
tabsStore.closeOthers('/dashboard')
// Close all tabs
tabsStore.closeAll()
// Refresh tab
tabsStore.refreshTab('/dashboard')Layout Store
Manages layout configuration, including sidebar state and layout mode.
Location
src/stores/layout.ts
Actions
// Toggle sidebar collapse
layoutStore.toggleSidebar()
// Set layout mode
layoutStore.setLayoutMode('horizontal')
// Detect device type
layoutStore.detectDevice()Other Stores
Settings Store
src/stores/settings.ts - User personalization settings
Notification Store
src/stores/notification.ts - Message notification center
Dict Store
src/stores/dict.ts - Dictionary data cache
Store Composition
In actual development, multiple Stores often work together:
Login Flow Example
import { useAuthStore } from '@/stores/auth'
import { usePermissionStore } from '@/stores/permission'
import { useTabsStore } from '@/stores/tabs'
const handleLogin = async (values) => {
try {
// 1. Login authentication
await authStore.login(values.username, values.password)
// 2. Generate permission routes
await permissionStore.generateRoutes()
// 3. Clear previous tabs
tabsStore.closeAll()
// 4. Redirect to home
router.push('/')
} catch (error) {
message.error('Login failed')
}
}Best Practices
1. Use storeToRefs for Destructuring
// ✅ Correct: Maintain reactivity
const { count, doubleCount } = storeToRefs(store)
// ❌ Incorrect: Lose reactivity
const { count, doubleCount } = store2. Don't Modify State Outside Store
// ✅ Correct: Modify through Action
store.increment()
// ❌ Incorrect: Direct modification
store.count++3. Single Responsibility for Stores
Each Store should only manage state for one domain:
auth- Only authentication relatedtheme- Only theme relatedtabs- Only tabs related
Next Steps
- Learn Development Workflow for project standards
- Study API Integration for backend connection
- View Utils for utility functions
