🔥 Pinia 入门:开启高效状态管理的魔法之门!

288 阅读2分钟

vue里面添加pinia.png

以下是几个 Pinia 的应用案例,帮助你理解如何在 Vue 3 项目中使用 Pinia 进行状态管理。


案例 1:用户认证状态管理

场景:管理用户的登录状态、用户信息,并提供登录和退出功能。

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

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

export const useAuthStore = defineStore('auth', {
  state: () => ({
    user: null as User | null,
    isAuthenticated: false,
  }),
  actions: {
    async login(email: string, password: string) {
      // 模拟 API 调用
      const response = await fakeApiLogin(email, password)
      this.user = response.user
      this.isAuthenticated = true
    },
    logout() {
      this.user = null
      this.isAuthenticated = false
    },
  },
  getters: {
    userName: (state) => state.user?.name || 'Guest',
  },
})

在组件中使用

<script setup>
import { useAuthStore } from '@/stores/auth'

const auth = useAuthStore()

// 登录操作
const handleLogin = async () => {
  await auth.login('user@example.com', 'password')
  console.log(auth.userName) // 输出用户名称
}
</script>

案例 2:购物车管理

场景:管理用户的购物车商品、总价和操作。

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

interface Product {
  id: number
  name: string
  price: number
}

interface CartItem extends Product {
  quantity: number
}

export const useCartStore = defineStore('cart', {
  state: () => ({
    items: [] as CartItem[],
  }),
  getters: {
    totalPrice: (state) =>
      state.items.reduce((sum, item) => sum + item.price * item.quantity, 0),
  },
  actions: {
    addToCart(product: Product) {
      const existing = this.items.find((item) => item.id === product.id)
      if (existing) {
        existing.quantity++
      } else {
        this.items.push({ ...product, quantity: 1 })
      }
    },
    removeItem(productId: number) {
      this.items = this.items.filter((item) => item.id !== productId)
    },
    clearCart() {
      this.items = []
    },
  },
})

在组件中使用

<template>
  <div v-for="item in cart.items" :key="item.id">
    {{ item.name }} × {{ item.quantity }}
  </div>
  <p>总价: {{ cart.totalPrice }}</p>
  <button @click="cart.addToCart(newProduct)">添加商品</button>
</template>

<script setup>
import { useCartStore } from '@/stores/cart'

const cart = useCartStore()
const newProduct = { id: 1, name: '商品A', price: 100 }
</script>

案例 3:全局主题切换

场景:管理应用的主题(亮色/暗色模式)。

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

export const useThemeStore = defineStore('theme', {
  state: () => ({
    isDarkMode: false,
  }),
  actions: {
    toggleTheme() {
      this.isDarkMode = !this.isDarkMode
      // 可选:保存到 localStorage
      localStorage.setItem('theme', this.isDarkMode ? 'dark' : 'light')
    },
  },
})

在组件中使用

<template>
  <button @click="theme.toggleTheme">
    {{ theme.isDarkMode ? '切换到亮色' : '切换到暗色' }}
  </button>
</template>

<script setup>
import { useThemeStore } from '@/stores/theme'
const theme = useThemeStore()
</script>

案例 4:异步数据加载

场景:管理 API 数据的加载状态和错误处理。

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

interface Post {
  id: number
  title: string
  content: string
}

export const usePostStore = defineStore('posts', {
  state: () => ({
    posts: [] as Post[],
    isLoading: false,
    error: null as string | null,
  }),
  actions: {
    async fetchPosts() {
      this.isLoading = true
      try {
        const response = await fetch('https://api.example.com/posts')
        this.posts = await response.json()
      } catch (error) {
        this.error = '加载失败'
      } finally {
        this.isLoading = false
      }
    },
  },
})

在组件中使用

<template>
  <div v-if="posts.isLoading">加载中...</div>
  <div v-else-if="posts.error">{{ posts.error }}</div>
  <div v-else v-for="post in posts.posts" :key="post.id">
    {{ post.title }}
  </div>
</template>

<script setup>
import { usePostStore } from '@/stores/posts'

const posts = usePostStore()
onMounted(() => posts.fetchPosts())
</script>

高级用法:组合 Store

将多个 Store 组合使用,例如在用户登录后加载购物车数据:

// 组合使用 AuthStore 和 CartStore
import { useAuthStore } from '@/stores/auth'
import { useCartStore } from '@/stores/cart'

const auth = useAuthStore()
const cart = useCartStore()

// 用户登录后加载购物车
watch(
  () => auth.isAuthenticated,
  (isAuthenticated) => {
    if (isAuthenticated) {
      cart.loadCartData(auth.user.id)
    }
  }
)

总结

Pinia 的核心优势:

  1. 类型安全:天然支持 TypeScript。
  2. 模块化:通过多个 Store 管理不同功能。
  3. 灵活组合:可在组件或 Store 之间复用逻辑。
  4. 轻量简洁:API 设计简单,学习成本低。

适用于需要全局状态管理的场景,如用户信息、主题、购物车、API 数据缓存等。