使用 Pinia 的五个技巧

本文分享了在使用Pinia时的五个实用技巧,包括避免无用getter、利用OptionStores中的组合式函数、在SetupStores中处理复杂逻辑、注入全局变量以及处理私有状态和SSR中的客户端状态。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

在这篇文章中,想与大家分享使用 Pinia 的五大技巧。

以下是简要总结:

  1. 不要创建无用的 getter
  2. 在 Option Stores 中使用组合式函数(composables)
  3. 对于复杂的组合式函数,使用 Setup Stores
  4. 使用 Setup Stores 注入全局变量,如路由器(Router)
  5. 如何创建私有状态

1、不要创建无用的 getter

你并不需要为所有事情使用 getter。在 Vuex 中有一个普遍的误解,认为你应该总是通过 getter 访问状态。

这是不正确的。

当你需要从状态中计算出某些东西时,getter 是有用的,例如,如果你有一个待办事项列表,想知道有多少已完成,你可以为此创建一个 getter。

在生产代码中经常看到过这样的代码:

export default Vuex.Store({
  state: () => ({ counter: 0 }),
  getters: {
    // 完全无用的 getter
    getCount: state => state.counter,
  },
})

这在 Vuex 中只是不必要的样板代码,在 Pinia 中也是如此。你可以直接访问状态:

const counterStore = useCounterStore()
counterStore.counter // 0 ✅

PS:大多数时候你不需要 storeToRefs()(或 toRef())。你可以直接使用 store,Vue 的响应式真的很方便 😄。

2、在 Option Stores 中使用组合式函数

你可以在 option stores 中使用一些组合式函数,特别是那些持有状态且可写的组合式函数。例如,你可以使用 @vueuse/core 的 useLocalStorage() 将一些状态存储在浏览器的本地存储中。

import { useLocalStorage } from '@vueuse/core'
const useAuthStore = defineStore('auth', {
  state: () => ({
    user: useLocalStorage('pinia/user/login', 'alice'),
  }),
})

或者使用 refDebounced() 对 ref 的更改进行防抖处理:

import { refDebounced } from '@vueuse/core'
const useSearchStore = defineStore('search', {
  state: () => ({
    user: {
      text: refDebounced(/* ... */),
    },
  }),
})

3、在 Setup Stores 中使用复杂的组合式函数

在 Setup stores 中,你可以使用任何你想要的组合式函数。你可以连接到 websocket、蓝牙处理或甚至游戏手柄!

import { useWebSocket } from '@vueuse/core'
export const useServerInfoStore = defineStore('server-info', () => {
  const { status, data, send, open, close } = useWebSocket('ws://websocketurl')
  return {
    status,
    data,
    send,
    open,
    close,
  }
})

Pinia 会自动识别哪些是状态、getter 或动作。记住,必须从 setup 函数返回所有状态属性。

在 setup stores 中使用 inject()

你可以在 setup stores 中使用 inject() 来访问应用级别提供的变量,如路由器实例:

import { useRouter } from 'vue-router'
export const useAuthStore('auth', () => {
  const router = useRouter()
  function logout() {
    // 登出用户
    return router.push('/login')
  }
  return {
    logout
  }
})
使用嵌套 Stores 创建私有状态

setup stores 的一个黄金规则是返回每一个状态片段:

export const useAuthStore('auth', () => {
  const user = ref<User | null>(null)
  const token = ref<string | null>(null)
  // 我们必须返回 user 和 token
  return {
    user,
    token,
  }
})

但如果我们想要隐藏一些 store 中的状态怎么办?我们可以创建一个包含私有状态的嵌套 store:

export const usePrivateAuthState('auth-private', () => {
  const token = ref<string | null>(null)
  return {
    token,
  }
})
export const useAuthStore('auth', () => {
  const user = ref<User | null>(null)
  const privateState = usePrivateAuthState()
  privateState.token // 仅在此 store 中可访问
  return {
    user,
  }
})
在 SSR 中使用仅客户端状态

服务器端渲染(SSR)是提高应用性能的绝佳方式。然而,与仅客户端应用相比,它带来了一些额外的困难。例如,你无法访问 window、document 或任何其他特定于浏览器的 API,如本地存储。

在 Option Stores 中,这要求你使用 hydrate 选项告诉 Pinia 某些状态不应在客户端上进行 hydrate:

import { useLocalStorage } from '@vueuse/core'
const useAuthStore = defineStore('auth', {
  state: () => ({
    user: useLocalStorage('pinia/user/login', 'alice'),
  }),
  hydrate(state, initialState) {
    state.user = useLocalStorage('pinia/user/login', 'alice')
  },
})

在 Setup Stores 中,你可以使用 skipHydrate 辅助函数标记某些状态为仅客户端状态:

import { defineStore, skipHydrate } from 'pinia'
const useAuthStore = defineStore('auth', () => {
  const user = skipHydrate(useLocalStorage('pinia/user/login', 'alice'))
  return { user }
})

总结

当然还有许多其他的技巧可以分享,但这些是我认为比较有用的。此外,大多数人对它们并不了解。你有没有发现任何有用的 Pinia 技巧或窍门?

<think>嗯,用户要求提供Pinia使用教程。在准备回答时,我注意到这是个具体的技术请求,用户已经显示了使用Vue3背景,因为提问中明确提到了"Vue3"。Pinia是Vue3的官方推荐状态管理库,因此我的回答需要从基本概念到实际代码展示逐步展开。为了增强可信度,我将引用多个知识片段:引用[1]说明Pinia的角色及其优势;引用[2]强调其API设计理念;引用[3]展示核心state操作;引用[4]提供组件集成示例。用户希望了解使用方法和教程,这意味着结构要清晰:先介绍核心概念(store/state/actions),再展示创建过程,最后演示组件集成。在回复中会穿插提示:项目创建步骤可以适当简化说明,重点在于store定义和组件的实际使用方法。为满足格式要求,所有代码变量都用$...$包裹,比如定义函数名用$defineStore$。独立代码块使用多行格式。特别需要说明store定义时,引用[3]强调"必须在setupstore中返回state的所有属性",这点将转化为代码注释中的注意事项。组件交互部分将展示两种典型场景:显示state值${{stockStore.stock}}$和触发action$@click="stockStore.addStock()"$。最后需要补充拓展性问题,例如优化异步操作策略,这是实际开发中的常见痛点。由于用户要求生成相关问题,这里设计为进阶方向:状态持久化、测试方法等,便于用户后续探索。这些问题的排序是从基础使用过渡到高级技巧,整体形成学习路径。</think> 以下是 **Pinia 在 Vue 3 中的完整使用指南**,结合核心概念与最佳实践逐步说明: --- ### 一、Pinia 核心概念 1. **Store (状态仓库)** - 每个 Store 是独立的状态模块,代替 Vuex 的模块化设计[^1] - 通过 `defineStore()` 创建,需提供唯一 ID 和配置对象[^2] ```javascript // stores/counter.js import { defineStore } from 'pinia' export const useCounterStore = defineStore('counter', { state: () => ({ count: 0 }), // 响应式状态 getters: { doubleCount: (state) => state.count * 2 // 计算属性 }, actions: { increment() { this.count++ } // 修改状态的方法 } }) ``` 2. **State 与响应式** - State 必须是返回初始状态的**函数**(类似组件的 `data()`)[^3] - 修改状态推荐通过 `actions`,但直接赋值也有效: ```javascript // 直接修改示例 const store = useCounterStore() store.count = 5 // 有效但破坏封装性 ``` --- ### 二、在组件中使用 Store #### 1. 基础使用(Options API) ```vue <script> import { useCounterStore } from '@/stores/counter' export default { setup() { const counterStore = useCounterStore() return { counterStore } }, computed: { quadrupleCount() { return this.counterStore.doubleCount * 2 } } } </script> <template> <p>Count: {{ counterStore.count }}</p> <button @click="counterStore.increment()">+1</button> </template> ``` #### 2. Composition API 优化(推荐) ```vue <script setup> import { useCounterStore } from '@/stores/counter' import { storeToRefs } from 'pinia' // 解构保持响应式 const counterStore = useCounterStore() const { count, doubleCount } = storeToRefs(counterStore) // 响应式解构 </script> <template> <p>Count: {{ count }}</p> <p>Double: {{ doubleCount }}</p> </template> ``` --- ### 三、进阶技巧 #### 1. 异步 Action 处理 ```javascript // store 中定义异步操作 actions: { async fetchData() { const res = await fetch('/api/data') this.data = await res.json() // 直接修改 state } } ``` #### 2. 跨 Store 调用 ```javascript import { useAuthStore } from './authStore' actions: { checkout() { const auth = useAuthStore() if (!auth.isLoggedIn) throw new Error('请登录') // ...结算逻辑 } } ``` #### 3. 状态持久化(插件) 使用 `pinia-plugin-persistedstate`: ```javascript import piniaPluginPersistedstate from 'pinia-plugin-persistedstate' const pinia = createPinia() pinia.use(piniaPluginPersistedstate) // Store 配置 defineStore('cart', { state: () => ({ items: [] }), persist: true // 自动 localStorage 持久化 }) ``` --- ### 四、与 Vuex 的对比优势 | 特性 | Pinia | Vuex | |--------------|------------------------|--------------| | API 复杂度 | ⭐ 更简洁 | ⭐⭐⭐ 较复杂 | | TypeScript | ⭐⭐⭐ 原生支持 | ⭐ 需额外配置 | | 模块化 | 自动代码分割 | 需手动分模块 | | 异步处理 | Action 直接支持 async | 需配合插件 | > **总结**:Pinia 精简了状态管理流程,尤其适合 Vue 3 项目[^1][^2]。通过组合式 API 可实现更灵活的状态逻辑复用,同时保持 TypeScript 类型推断完整。 --- ### 相关问题 1. Pinia 如何实现与 Vue DevTools 的集成调试? 2. 在服务端渲染 (SSR) 场景下使用 Pinia 有哪些注意事项? 3. 如何用 Pinia 实现跨组件通信? 4. Pinia 的插件机制支持哪些扩展能力? 5. Vuex 迁移到 Pinia 的关键步骤是什么?
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值