vue3【pinia】环境搭建、存储读取修改数据、storeToRefs、getters、$subscribe、store组合式写法

Vue3之pinia系列:环境搭建、存储读取修改数据、其他使用场景

1、pinia环境搭建

(1)准备一个效果

  • 要求:两个组件,一个组件求和,另一个组件生产随机文本;
    在这里插入图片描述

(2)搭建 pinia 环境

第一步:npm install pinia

第二步:操作src/main.ts

import { createApp } from 'vue'
import App from './App.vue'

/* 引入createPinia,用于创建pinia */
import { createPinia } from 'pinia'

/* 创建pinia */
const pinia = createPinia()
const app = createApp(App)

/* 使用插件 */{}
app.use(pinia)
app.mount('#app')

此时开发者工具中已经有了pinia选项
在这里插入图片描述

2、存储读取修改数据

(1)存储+读取数据

  1. Store是一个保存:状态业务逻辑 的实体,每个组件都可以读取写入它。

  2. 它有三个概念:stategetteraction,相当于组件中的: datacomputedmethods

  3. 具体编码:src/store/count.ts

    // 引入defineStore用于创建store
    import {defineStore} from 'pinia'
    
    // 定义并暴露一个store
    export const useCountStore = defineStore('count',{
      // 动作
      actions:{},
      // 状态
      state(){
        return {
          sum:6
        }
      },
      // 计算
      getters:{}
    })
    
  4. 具体编码:src/store/talk.ts

    // 引入defineStore用于创建store
    import {defineStore} from 'pinia'
    
    // 定义并暴露一个store
    export const useTalkStore = defineStore('talk',{
      // 动作
      actions:{},
      // 状态
      state(){
        return {
          talkList:[
            {id:'yuysada01',content:'你今天有点怪,哪里怪?怪好看的!'},
         		{id:'yuysada02',content:'草莓、蓝莓、蔓越莓,你想我了没?'},
            {id:'yuysada03',content:'心里给你留了一块地,我的死心塌地'}
          ]
        }
      },
      // 计算
      getters:{}
    })
    
  5. 组件中使用state中的数据

    <template>
      <h2>当前求和为:{{ sumStore.sum }}</h2>
    </template>
    
    <script setup lang="ts" name="Count">
      // 引入对应的useXxxxxStore	
      import {useSumStore} from '@/store/sum'
      
      // 调用useXxxxxStore得到对应的store
      const sumStore = useSumStore()
    </script>
    
    <template>
    	<ul>
        <li v-for="talk in talkStore.talkList" :key="talk.id">
          {{ talk.content }}
        </li>
      </ul>
    </template>
    
    <script setup lang="ts" name="Count">
      import axios from 'axios'
      import {useTalkStore} from '@/store/talk'
    
      const talkStore = useTalkStore()
    </script>
    

(2)修改数据(三种方式)

  1. 第一种修改方式,直接修改

    countStore.sum = 666
    
  2. 第二种修改方式:批量修改

    countStore.$patch({
      sum:999,
      school:'csdn'
    })
    
  3. 第三种修改方式:借助action修改(action中可以编写一些业务逻辑)

    import { defineStore } from 'pinia'
    
    export const useCountStore = defineStore('count', {
      /*************/
      actions: {
        //加
        increment(value:number) {
          if (this.sum < 10) {
            //操作countStore中的sum
            this.sum += value
          }
        },
        //减
        decrement(value:number){
          if(this.sum > 1){
            this.sum -= value
          }
        }
      },
      /*************/
    })
    

    组件中调用action即可

    // 使用countStore
    const countStore = useCountStore()
    
    // 调用对应action
    countStore.increment(10)
    

3、其他使用场景

(1)storeToRefs

  • 借助storeToRefsstore中的数据转为ref对象,方便在模板中使用。
  • 注意:pinia提供的storeToRefs只会将数据做转换,而VuetoRefs会转换store中数据。
<template>
	<div class="count">
		<h2>当前求和为:{{sum}}</h2>
	</div>
</template>

<script setup lang="ts" name="Count">
  import { useCountStore } from '@/store/count'
  /* 引入storeToRefs */
  import { storeToRefs } from 'pinia'

	/* 得到countStore */
  const countStore = useCountStore()
  /* 使用storeToRefs转换countStore,随后解构 */
  const {sum} = storeToRefs(countStore)
</script>

(2)getters

  1. 概念:当state中的数据,需要经过处理后再使用时,可以使用getters配置。

  2. 追加getters配置。

    // 引入defineStore用于创建store
    import {defineStore} from 'pinia'
    
    // 定义并暴露一个store
    export const useCountStore = defineStore('count',{
      // 动作
      actions:{
        /************/
      },
      // 状态
      state(){
        return {
          sum:1,
          school:'atguigu'
        }
      },
      // 计算
      getters:{
        bigSum:(state):number => state.sum *10,
        upperSchool():string{
          return this. school.toUpperCase()
        }
      }
    })
    
  3. 组件中读取数据:

    const {increment,decrement} = countStore
    let {sum,school,bigSum,upperSchool} = storeToRefs(countStore)
    

(3)$subscribe

通过 store 的 $subscribe() 方法侦听 state 及其变化

talkStore.$subscribe((mutate,state)=>{
  console.log('LoveTalk',mutate,state)
  localStorage.setItem('talk',JSON.stringify(talkList.value))
})

(4)store组合式写法

import {defineStore} from 'pinia'
import axios from 'axios'
import {nanoid} from 'nanoid'
import {reactive} from 'vue'

export const useTalkStore = defineStore('talk',()=>{
  // talkList就是state
  const talkList = reactive(
    JSON.parse(localStorage.getItem('talkList') as string) || []
  )

  // getATalk函数相当于action
  async function getATalk(){
    // 发请求,下面这行的写法是:连续解构赋值+重命名
    let {data:{content:title}} = await axios.get('https://api.uomg.com/api/rand.qinghua?format=json')
    // 把请求回来的字符串,包装成一个对象
    let obj = {id:nanoid(),title}
    // 放到数组中
    talkList.unshift(obj)
  }
  return {talkList,getATalk}
})
<think>好的,我现在需要回答用户关于在Vue中使用Pinia的问题。用户之前遇到了路由参数传递的问题,现在转向状态管理库Pinia的询问。首先,我需要确定用户对Pinia的了解程度。可能他们之前用过Vuex,想迁移到Pinia,或者刚开始接触状态管理。 首先,我应该介绍Pinia的基本概念,说明它和Vuex的关系,强调Pinia是官方推荐的状态管理工具,支持Vue2和Vue3。接着,需要分步骤讲解如何使用Pinia,包括安装、创建Store、在组件中使用,以及核心功能如状态、Getters、Actions。 用户可能有疑问,比如PiniaVuex的区别,为什么要用Pinia,或者如何组织多个Store。我需要覆盖这些常见问题,同时提供代码示例,确保用户能跟着操作。考虑到用户之前的路由问题,可能对配置过程比较敏感,所以安装步骤要详细,包括包管理器的命令。 在示例部分,需要展示一个典型的Store结构,比如用户信息的存储,包括state、getter和action。然后演示如何在组件中导入和使用,包括如何访问状态、调用actions。可能还需要提到组合式API和选项式API的不同用法,因为用户可能使用不同风格的Vue。 另外,用户可能会遇到响应式丢失的问题,需要提醒使用storeToRefs来解构保持响应式。插件和持久化存储也是常见需求,可以简要介绍如何通过插件实现,比如vuex-persistedstate的替代方案。 最后,总结Pinia的优势,比如TypeScript支持、模块化、易用性等,帮助用户理解迁移或采用的原因。确保语言简洁,结构清晰,避免技术术语过多,必要时提供代码块和注意事项。</think>以下是 VuePinia 状态管理库的深度使用指南,包含最新实践方案和关键细节说明: --- ### 📦 一、核心优势对比 | 特性 | Pinia | Vuex | |--------------------|-------------------------|------------------| | **Vue3支持** | 原生支持 | 需Vuex4 | | **TypeScript** | 零配置完美支持 | 需额外声明 | | **API设计** | 组合式+选项式 | 仅选项式 | | **模块化** | 自动代码分割 | 需手动注册模块 | | **包体积** | 1KB (gzip) | 10KB+ | --- ### 🛠️ 二、快速集成方案 1. **安装命令**(推荐pnpm): ```bash pnpm add pinia # 或 npm install pinia ``` 2. **初始化配置**(main.js/ts): ```typescript import { createApp } from &#39;vue&#39; import { createPinia } from &#39;pinia&#39; const app = createApp(App) const pinia = createPinia() // 可选:注册持久化插件 pinia.use(piniaPluginPersistedstate) app.use(pinia) app.mount(&#39;#app&#39;) ``` --- ### 🔨 三、Store创建规范 #### 1. 标准Store模板 ```typescript // stores/user.ts import { defineStore } from &#39;pinia&#39; export const useUserStore = defineStore(&#39;user&#39;, { // 推荐使用箭头函数保证类型推断 state: () => ({ id: 0, name: &#39;Guest&#39;, token: localStorage.getItem(&#39;token&#39;) || &#39;&#39;, permissions: [] as string[] // 类型断言 }), getters: { isAdmin: (state) => state.permissions.includes(&#39;admin&#39;), // 带参数的计算属性 hasPermission: (state) => (code: string) => { return state.permissions.includes(code) } }, actions: { async login(payload: { username: string; password: string }) { const { data } = await api.login(payload) this.token = data.token this.name = data.username localStorage.setItem(&#39;token&#39;, data.token) }, logout() { // 批量修改建议使用$patch this.$patch({ token: &#39;&#39;, permissions: [] }) localStorage.removeItem(&#39;token&#39;) } }, // 持久化配置(需安装插件) persist: { paths: [&#39;token&#39;], // 仅持久化token字段 storage: sessionStorage // 切换存储介质 } }) ``` #### 2. 组合式StoreVue3推荐) ```typescript export const useCounterStore = defineStore(&#39;counter&#39;, () => { const count = ref(0) const double = computed(() => count.value * 2) function increment(step = 1) { count.value += step } return { count, double, increment } }) ``` --- ### 🎯 四、组件中使用指南 #### 1. 基础调用 ```vue <script setup> import { useUserStore } from &#39;@/stores/user&#39; const userStore = useUserStore() // 直接访问状态 console.log(userStore.name) // 调用action const handleLogin = async () => { await userStore.login({ username: &#39;admin&#39;, password: &#39;123456&#39; }) } // 使用带参数的getter const hasEditPermission = userStore.hasPermission(&#39;edit&#39;) </script> <template> <div v-if="userStore.isAdmin">管理员面板</div> <button @click="userStore.increment()">点击计数: {{ userStore.count }}</button> </template> ``` #### 2. 响应式解构技巧 ```typescript import { storeToRefs } from &#39;pinia&#39; const userStore = useUserStore() const { name, token } = storeToRefs(userStore) // 保持响应式 const { login } = userStore // 方法无需处理 ``` --- ### 🔧 五、高级实践技巧 #### 1.Store调用 ```typescript // stores/cart.ts export const useCartStore = defineStore(&#39;cart&#39;, { actions: { async checkout() { const user = useUserStore() if (!user.isLoggedIn) { await user.loginAnonymously() } // 调用其他store逻辑... } } }) ``` #### 2. 状态热更新(HMR) ```typescript // vite.config.ts import { defineConfig } from &#39;vite&#39; export default defineConfig({ plugins: [ vue({ template: { compilerOptions: { // 启用Pinia热更新 isCustomElement: (tag) => tag.startsWith(&#39;router-&#39;) } } }) ] }) ``` #### 3. 严格模式调试 ```typescript const pinia = createPinia() // 开发环境启用严格模式 if (import.meta.env.DEV) { pinia.use(({ store }) => { store.$subscribe((mutation, state) => { console.debug(&#39;[Pinia] Mutation:&#39;, mutation.type, mutation.payload) }) }) } ``` --- ### ⚠️ 六、常见问题排查 #### 1. 响应性丢失问题 **错误示例**: ```typescript const { count } = useCounterStore() // ❌ 失去响应式 ``` **正确方案**: ```typescript const counterStore = useCounterStore() // 方案1:直接使用store.count // 方案2:使用storeToRefs解构 const { count } = storeToRefs(counterStore) ``` #### 2. 循环依赖处理 当Store A 引用 Store B,同时 Store B 引用 Store A 时: ```typescript // 在函数内动态引用 actions: { fetchData() { const storeB = useStoreB() // 在方法内部引用 // ... } } ``` #### 3. SSR兼容方案 ```typescript // nuxt.config.ts export default defineNuxtConfig({ modules: [&#39;@pinia/nuxt&#39;], pinia: { autoImports: [ &#39;defineStore&#39;, [&#39;defineStore&#39;, &#39;definePiniaStore&#39;] // 别名配置 ] } }) ``` --- ### 📚 七、生态推荐 1. **持久化插件** `pinia-plugin-persistedstate`:数据持久化存储 ```bash pnpm add pinia-plugin-persistedstate ``` 2. **调试工具** 安装 [Vue Devtools](https://devtools.vuejs.org/) 可直观查看Pinia状态树 3. **测试工具** `@pinia/testing`:提供单元测试支持 ```typescript import { setActivePinia } from &#39;pinia&#39; beforeEach(() => { setActivePinia(createPinia()) }) ``` --- 通过以上方案,您可以高效管理Vue应用中的复杂状态逻辑。Pinia的轻量化和TypeScript友好特性使其成为新一代Vue项目的首选状态管理工具。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值