vue.js

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript类库 > vue.js > Vue Pinia状态管理

Vue中Pinia状态管理的四大实战场景指南

作者:fruge365

Pinia 是 Vue 官方推荐的状态管理库,这篇文章主要为大家详细介绍了Vue中Pinia状态管理的四大实战场景,感兴趣的小伙伴可以了解一下

为什么选择 Pinia

Pinia 是 Vue 官方推荐的状态管理库,相比 Vuex 有以下优势:

基础使用

安装和配置

npm install pinia
// main.js
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'

const app = createApp(App)
app.use(createPinia())
app.mount('#app')

定义 Store

// stores/counter.js
import { defineStore } from 'pinia'

export const useCounterStore = defineStore('counter', {
  state: () => ({
    count: 0,
    name: 'Counter'
  }),
  
  getters: {
    doubleCount: (state) => state.count * 2,
    greeting: (state) => `Hello, ${state.name}!`
  },
  
  actions: {
    increment() {
      this.count++
    },
    
    async fetchData() {
      // 异步操作
      const data = await fetch('/api/data')
      this.count = data.count
    }
  }
})

在组件中使用

<template>
  <div>
    <p>计数: {{ counter.count }}</p>
    <p>双倍: {{ counter.doubleCount }}</p>
    <button @click="counter.increment()">增加</button>
  </div>
</template>

<script setup>
import { useCounterStore } from '@/stores/counter'

const counter = useCounterStore()
</script>

四个实战场景

1. 用户状态管理

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

export const useUserStore = defineStore('user', {
  state: () => ({
    user: null,
    token: localStorage.getItem('token'),
    isLoading: false
  }),
  
  getters: {
    isAuthenticated: (state) => !!state.token,
    userName: (state) => state.user?.name || '游客'
  },
  
  actions: {
    async login(credentials) {
      this.isLoading = true
      try {
        const response = await fetch('/api/login', {
          method: 'POST',
          body: JSON.stringify(credentials)
        })
        const data = await response.json()
        
        this.user = data.user
        this.token = data.token
        localStorage.setItem('token', data.token)
      } finally {
        this.isLoading = false
      }
    },
    
    logout() {
      this.user = null
      this.token = null
      localStorage.removeItem('token')
    }
  }
})

2. 购物车功能

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

export const useCartStore = defineStore('cart', {
  state: () => ({
    items: []
  }),
  
  getters: {
    totalItems: (state) => state.items.reduce((sum, item) => sum + item.quantity, 0),
    totalPrice: (state) => state.items.reduce((sum, item) => sum + item.price * item.quantity, 0)
  },
  
  actions: {
    addItem(product) {
      const existingItem = this.items.find(item => item.id === product.id)
      
      if (existingItem) {
        existingItem.quantity++
      } else {
        this.items.push({ ...product, quantity: 1 })
      }
    },
    
    removeItem(productId) {
      const index = this.items.findIndex(item => item.id === productId)
      if (index > -1) {
        this.items.splice(index, 1)
      }
    },
    
    clearCart() {
      this.items = []
    }
  }
})

3. 主题设置

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

export const useThemeStore = defineStore('theme', {
  state: () => ({
    isDark: localStorage.getItem('theme') === 'dark'
  }),
  
  getters: {
    theme: (state) => state.isDark ? 'dark' : 'light'
  },
  
  actions: {
    toggleTheme() {
      this.isDark = !this.isDark
      localStorage.setItem('theme', this.theme)
      document.documentElement.setAttribute('data-theme', this.theme)
    },
    
    setTheme(theme) {
      this.isDark = theme === 'dark'
      localStorage.setItem('theme', theme)
      document.documentElement.setAttribute('data-theme', theme)
    }
  }
})

4. API 数据管理

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

export const usePostsStore = defineStore('posts', {
  state: () => ({
    posts: [],
    loading: false,
    error: null
  }),
  
  getters: {
    publishedPosts: (state) => state.posts.filter(post => post.published),
    getPostById: (state) => (id) => state.posts.find(post => post.id === id)
  },
  
  actions: {
    async fetchPosts() {
      this.loading = true
      this.error = null
      
      try {
        const response = await fetch('/api/posts')
        this.posts = await response.json()
      } catch (error) {
        this.error = error.message
      } finally {
        this.loading = false
      }
    },
    
    async createPost(postData) {
      const response = await fetch('/api/posts', {
        method: 'POST',
        body: JSON.stringify(postData)
      })
      const newPost = await response.json()
      this.posts.push(newPost)
    }
  }
})

Pinia vs Vuex 对比

特性PiniaVuex
API 复杂度简单直观相对复杂
TypeScript原生支持需要额外配置
模块化天然模块化需要 modules
状态修改直接修改必须通过 mutations
异步操作actions 中直接处理需要 actions + mutations
// Pinia - 简洁直观
const store = useStore()
store.count++
store.updateUser(userData)

// Vuex - 需要 commit
store.commit('INCREMENT')
store.dispatch('updateUser', userData)

最佳实践

1. Store 命名规范

// 推荐:use + 功能名 + Store
export const useUserStore = defineStore('user', {})
export const useCartStore = defineStore('cart', {})
export const useThemeStore = defineStore('theme', {})

2. 状态结构设计

// 推荐:扁平化状态结构
state: () => ({
  user: null,
  isLoading: false,
  error: null
})

// 避免:过度嵌套
state: () => ({
  user: {
    profile: {
      personal: {
        name: ''
      }
    }
  }
})

3. 组合多个 Store

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

const userStore = useUserStore()
const cartStore = useCartStore()

// 可以在 actions 中调用其他 store
const handlePurchase = () => {
  if (userStore.isAuthenticated) {
    cartStore.clearCart()
  }
}
</script>

4. 持久化存储

// 简单的持久化实现
export const useSettingsStore = defineStore('settings', {
  state: () => ({
    language: 'zh-CN',
    notifications: true
  }),
  
  actions: {
    updateSettings(settings) {
      Object.assign(this, settings)
      localStorage.setItem('settings', JSON.stringify(this.$state))
    },
    
    loadSettings() {
      const saved = localStorage.getItem('settings')
      if (saved) {
        Object.assign(this, JSON.parse(saved))
      }
    }
  }
})

常见问题

1. 状态重置

// 重置整个 store
const store = useStore()
store.$reset()

// 重置特定状态
store.$patch({
  count: 0,
  name: ''
})

2. 监听状态变化

// 在组件中监听
import { watch } from 'vue'

const store = useStore()

watch(
  () => store.count,
  (newCount) => {
    console.log('Count changed:', newCount)
  }
)

3. 服务端渲染 (SSR)

// 在 SSR 中使用
export const useStore = defineStore('main', {
  state: () => ({
    data: null
  }),
  
  actions: {
    async hydrate() {
      if (process.client && !this.data) {
        await this.fetchData()
      }
    }
  }
})

总结

Pinia 的核心优势:

选择 Pinia,让 Vue 状态管理变得更加简单高效!

到此这篇关于Vue中Pinia状态管理的四大实战场景指南的文章就介绍到这了,更多相关Vue Pinia状态管理内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文