【vue3】03 - 公共数据管理pinia

【vue3】03 - 公共数据管理pinia

相当于vuex5!!
对于vuex3(对标vue2),可以看我的这个文章

一:vuex4.x和pinia

Vue 3 完全可以继续使用 Vuex,但需要注意以下几点:

1️⃣ Vuex 4.x 是 Vue 3 的兼容版本

  • Vuex 4.x 专为 Vue 3 设计,API 与 Vuex 3.x(Vue 2 的版本)几乎一致,但解决了 Vue 3 的兼容性问题。

  • 对于vuex 3.x可以参考我的这个文章

  • 安装命令:

    npm install vuex@next
    # 或
    yarn add vuex@next
    

2️⃣ Vuex 的未来

  • 官方推荐 Pinia:Pinia 是 Vue 团队推荐的状态管理库,相当于“Vuex 5”,专为 Vue 3 设计,支持 Composition API,且更简洁。
  • Vuex 进入维护模式:Vuex 不会增加新功能,但会继续修复 bug。

3️⃣ 如何选择?

  • 老项目迁移:如果已有 Vuex 代码,可以继续使用 Vuex 4.x。
  • 新项目:建议直接使用 Pinia(更轻量、TypeScript 友好,API 更简单)。

4️⃣ 示例对比

  • Vuex 4.x (Vue 3)

    import { createStore } from 'vuex';
    
    const store = createStore({
        state: { count: 0 },
        mutations: {
            increment(state) {
                state.count++;
            },
        },
    });
    
  • Pinia (推荐)

    import { defineStore } from 'pinia';
    
    // 定义counter变量,对于这个变量的操作有....
    // state -> 初始化
    // actions -> 相关方法
    export const useCounterStore = defineStore('counter', {
        state: () => ({ count: 0 }),
        actions: {
            increment() {
                this.count++;
            },
        },
    });
    

总结

  • 能用:Vuex 4.x 可以在 Vue 3 中正常使用。
  • 推荐替代:Pinia 是更现代的解决方案,适合新项目。

二:Pinia环境的搭建

1️⃣ 下载pinia

npm install pinia

2️⃣ 操作src/main.js,对pinia进行引入和初始化

import './assets/main.css'

import { createApp } from 'vue'

// 引入根组件
import App from './App.vue'
// 引入路由
import router from './router'
// 1:引入 Pinia,作为全局状态管理,可以理解为vuex5
import { createPinia } from 'pinia'

// 通过 createApp 创建一个 Vue 应用程序
// 指定根组件 App.vue, 后面会将App.vue的内容渲染到index.html中的id=app上
const app = createApp(App)

// 2:创建pinia
const pinia = createPinia()

// 使用 router,对应用程序进行路由初始化
app.use(router)
// 3:使用pinia
app.use(pinia)

// 挂载到 DOM,绑定根容器 => id=app 上(在目录的最外城index.html中,模板html文件
app.mount('#app')

此时启动项目就能发现pinia图标

在这里插入图片描述

三:数据的读取和存储

  1. Store是一个保存:状态业务逻辑 的实体,每个组件都可以读取写入它。
  2. 它有三个概念:stategetteraction,相当于组件中的: datacomputedmethods
  3. 定义数据的存储:src/store/talk.ts
// 引入defineStore用于创建store
import {defineStore} from 'pinia'

// 创建store, state -> 数据(data), getters -> 计算属性(computed), actions -> 方法(methods)
export const useTalkStore = defineStore('talk', {
    // 状态 - 类比于vue2的data(), 类比于vuex中的state
    state: () => ({
        talkList: [
            {id: 1, name: '张三', age: 18},
            {id: 2, name: '李四', age: 19},
            {id: 3, name: '王五', age: 20}
        ]
    }),
    // 计算属性 - 类比于vue2的computed(), 类比于vuex中的getters
    getters: {

    },
    // 方法 - 类比于vue2的methods(), 类比于vuex中的actions
    actions: {

    }
})
  1. 对于数据的读取,在指定的vue组件中使用数据
<template>
<div class="home">
    <p>{{ count }}</p>
    <button @click="add">点我加一</button>
    <!-- 3:然后就能在上面使用了 -->
    <ul>
        <li v-for="talk in talkStore.talkList" :key="talk.id">
            {{ talk.name }} - {{ talk.age }}
    </li>
    </ul>
    </div>
</template>

<script lang="ts" setup name="Home">
    import {ref} from 'vue'
    // 1:对于pinia的使用
    import { useTalkStore } from "@/store/talk.ts";

    const count = ref(0)
    console.log(count)

    // 2:引入store, 通过暴露的名称拿到store信息
    const talkStore = useTalkStore()


    function add() {
        count.value++
    }
</script>

<style lang="scss" scoped>

</style>

四:数据修改的三种方式

1:直接进行修改

countStore.sum = 666

2:批量修改

countStore.$patch({ // 通过$patch关键字
    sum: 999,
    school: 'haha'
})

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
            }
        }
    },
    /*************/
})


// 组件中使用就可以了
// 使用countStore
const countStore = useCountStore()

// 调用对应action
countStore.incrementOdd(n.value)

五:storeToRefs

  • 类比于vuex3中的toRef和toRefs
  • 借助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>

六:getters

state中的数据,需要经过处理后再使用时,可以使用getters配置。

类比于vue2的计算属性computed,等价于vuex3中的getter

// 引入defineStore用于创建store
import {defineStore} from 'pinia'

// 定义并暴露一个store
export const useCountStore = defineStore('count',{
    // 动作
    actions:{
        /************/
    },
    // 状态
    state(){
        return {
            sum:1,
            school:'hello'
        }
    },
    // 计算
    getters:{
        bigSum:(state): number => state.sum *10,
        upperSchool(): string {
            return this.school.toUpperCase()
        }
    }
})
const {increment,decrement} = countStore

// 注意数据信息使用storeToRefs进行转换
let {sum,school,bigSum,upperSchool} = storeToRefs(countStore)

七:Pinia 中的 $subscribe()

$subscribe() 是 Pinia 状态管理库中的一个方法,用于订阅 store 的状态变化。

它类似于 Vuex 的 subscribe 方法,但有一些 Pinia 特有的特性。

可以类比一下vue2中watch监视属性,但是有些不同

基本用法如下

import { useStore } from '@/stores/myStore'

const store = useStore()

const unsubscribe = store.$subscribe((mutation, state) => {
    // mutation 包含变更信息
    // state 是变更后的状态
    console.log('Store changed:', mutation, state)
})

// 当不再需要订阅时,可以调用返回的函数取消订阅
unsubscribe()

$subscribe() 可以接受第二个参数,是一个选项对象:

store.$subscribe((mutation, state) => {
    // 回调逻辑
}, {
    detached: true, // 当组件卸载时保持订阅 (默认为 false)
    deep: true,     // 深度监听状态变化 (默认为 false)
    flush: 'post'   // 回调触发时机 ('pre' | 'post' | 'sync')
})

和watch监听属性的区别

  1. $subscribe() 监听整个 store 的变化
  2. watch() 更适合监听特定的状态片段
  3. $subscribe() 可以获取变更的详细信息 (mutation 对象)

使用场景

  • 日志记录
  • 持久化状态到 localStorage
  • 同步多个 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(){
        // 发请求,下面这行的写法是:连续解构赋值+重命名
        // 解析出结果中的data中的content, 并且重命名为title
        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}
})
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值