Pinia 核心概念 #

概述 #

Pinia 只有三个核心概念,这使得它比其他状态管理库更简单易学:

text
Pinia 核心概念
├── State ────── 状态数据(类似 data)
├── Getters ──── 计算属性(类似 computed)
└── Actions ──── 方法(类似 methods)

State(状态) #

State 是 Store 的核心,用于存储应用的状态数据。

定义 State #

State 必须是一个返回初始状态的函数:

ts
import { defineStore } from 'pinia'

export const useUserStore = defineStore('user', {
  state: () => ({
    name: 'John',
    age: 25,
    email: 'john@example.com',
    isAdmin: false
  })
})

访问 State #

vue
<template>
  <div>
    <p>姓名: {{ userStore.name }}</p>
    <p>年龄: {{ userStore.age }}</p>
  </div>
</template>

<script setup>
import { useUserStore } from '@/stores/user'

const userStore = useUserStore()
</script>

解构 State #

直接解构会失去响应性,需要使用 storeToRefs

vue
<script setup>
import { storeToRefs } from 'pinia'
import { useUserStore } from '@/stores/user'

const userStore = useUserStore()

// 错误:失去响应性
const { name, age } = userStore

// 正确:保持响应性
const { name, age } = storeToRefs(userStore)
</script>

修改 State #

有多种方式修改 State:

ts
// 方式1:直接修改
userStore.name = 'Jane'

// 方式2:使用 $patch(批量修改)
userStore.$patch({
  name: 'Jane',
  age: 26
})

// 方式3:使用 $patch 函数(适合复杂逻辑)
userStore.$patch((state) => {
  state.name = 'Jane'
  state.age++
})

// 方式4:通过 Actions 修改(推荐)
userStore.updateProfile({ name: 'Jane', age: 26 })

重置 State #

使用 $reset 方法将 State 重置为初始值:

ts
const userStore = useUserStore()
userStore.$reset()

替换 State #

使用 $state 完全替换状态:

ts
userStore.$state = {
  name: 'New User',
  age: 30,
  email: 'new@example.com',
  isAdmin: true
}

Getters(计算属性) #

Getters 用于定义派生状态,类似于 Vue 的 computed 属性。

定义 Getters #

ts
export const useCounterStore = defineStore('counter', {
  state: () => ({
    count: 0
  }),
  getters: {
    // 基础 getter
    doubleCount: (state) => state.count * 2,
    
    // 使用 this 访问其他 getter
    doubleCountPlusOne() {
      return this.doubleCount + 1
    }
  }
})

访问其他 Store #

ts
export const useCartStore = defineStore('cart', {
  state: () => ({
    items: []
  }),
  getters: {
    summary() {
      const userStore = useUserStore()
      return `${userStore.name} 的购物车有 ${this.items.length} 件商品`
    }
  }
})

传递参数 #

Getters 本身不支持参数,但可以返回一个函数:

ts
export const useUserStore = defineStore('user', {
  state: () => ({
    users: [
      { id: 1, name: 'John' },
      { id: 2, name: 'Jane' },
      { id: 3, name: 'Bob' }
    ]
  }),
  getters: {
    getUserById: (state) => {
      return (id: number) => state.users.find(user => user.id === id)
    }
  }
})
vue
<template>
  <p>{{ userStore.getUserById(1)?.name }}</p>
</template>

TypeScript 类型 #

ts
interface User {
  id: number
  name: string
  email: string
}

export const useUserStore = defineStore('user', {
  state: () => ({
    users: [] as User[]
  }),
  getters: {
    userCount: (state): number => state.users.length,
    
    getUserById: (state) => (id: number): User | undefined => {
      return state.users.find(user => user.id === id)
    }
  }
})

Actions(方法) #

Actions 用于定义业务逻辑,可以包含同步和异步操作。

定义 Actions #

ts
export const useCounterStore = defineStore('counter', {
  state: () => ({
    count: 0
  }),
  actions: {
    increment() {
      this.count++
    },
    
    incrementBy(amount: number) {
      this.count += amount
    },
    
    reset() {
      this.count = 0
    }
  }
})

异步 Actions #

ts
export const useProductStore = defineStore('product', {
  state: () => ({
    products: [],
    loading: false,
    error: null
  }),
  actions: {
    async fetchProducts() {
      this.loading = true
      this.error = null
      
      try {
        const response = await fetch('/api/products')
        this.products = await response.json()
      } catch (error) {
        this.error = error.message
      } finally {
        this.loading = false
      }
    }
  }
})

调用其他 Actions #

ts
export const useCartStore = defineStore('cart', {
  state: () => ({
    items: [],
    total: 0
  }),
  actions: {
    addItem(item) {
      this.items.push(item)
      this.calculateTotal()
    },
    
    removeItem(itemId) {
      this.items = this.items.filter(item => item.id !== itemId)
      this.calculateTotal()
    },
    
    calculateTotal() {
      this.total = this.items.reduce((sum, item) => sum + item.price, 0)
    }
  }
})

访问其他 Store #

ts
export const useOrderStore = defineStore('order', {
  state: () => ({
    orders: []
  }),
  actions: {
    async createOrder() {
      const cartStore = useCartStore()
      const userStore = useUserStore()
      
      const order = {
        userId: userStore.id,
        items: cartStore.items,
        total: cartStore.total
      }
      
      // 创建订单...
      this.orders.push(order)
      
      // 清空购物车
      cartStore.clearCart()
    }
  }
})

使用 Composition API 风格 #

Actions 可以使用 async/await:

ts
export const useAuthStore = defineStore('auth', {
  state: () => ({
    user: null,
    token: null
  }),
  actions: {
    async login(credentials) {
      const response = await api.login(credentials)
      this.user = response.user
      this.token = response.token
    },
    
    async logout() {
      await api.logout()
      this.user = null
      this.token = null
    }
  }
})

完整示例 #

下面是一个完整的用户管理 Store 示例:

ts
// stores/user.ts
import { defineStore } from 'pinia'

interface User {
  id: number
  name: string
  email: string
  role: 'admin' | 'user'
}

interface UserState {
  users: User[]
  currentUser: User | null
  loading: boolean
  error: string | null
}

export const useUserStore = defineStore('user', {
  state: (): UserState => ({
    users: [],
    currentUser: null,
    loading: false,
    error: null
  }),
  
  getters: {
    userCount: (state) => state.users.length,
    
    isAdmin: (state) => state.currentUser?.role === 'admin',
    
    getUserById: (state) => (id: number) => {
      return state.users.find(user => user.id === id)
    },
    
    activeUsers: (state) => {
      return state.users.filter(user => user.email)
    }
  },
  
  actions: {
    async fetchUsers() {
      this.loading = true
      this.error = null
      
      try {
        const response = await fetch('/api/users')
        this.users = await response.json()
      } catch (error) {
        this.error = error.message
      } finally {
        this.loading = false
      }
    },
    
    async login(email: string, password: string) {
      this.loading = true
      this.error = null
      
      try {
        const response = await fetch('/api/login', {
          method: 'POST',
          body: JSON.stringify({ email, password })
        })
        this.currentUser = await response.json()
      } catch (error) {
        this.error = error.message
      } finally {
        this.loading = false
      }
    },
    
    logout() {
      this.currentUser = null
    },
    
    updateUser(id: number, updates: Partial<User>) {
      const index = this.users.findIndex(user => user.id === id)
      if (index !== -1) {
        this.users[index] = { ...this.users[index], ...updates }
      }
    }
  }
})

下一步 #

现在你已经掌握了 Pinia 的核心概念,接下来让我们深入学习如何定义和使用 Store。

最后更新:2026-03-28