【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图标
三:数据的读取和存储
Store
是一个保存:状态、业务逻辑 的实体,每个组件都可以读取、写入它。- 它有三个概念:
state
、getter
、action
,相当于组件中的:data
、computed
和methods
。 - 定义数据的存储:
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: {
}
})
- 对于数据的读取,在指定的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
- 借助
storeToRefs
将store
中的数据转为ref
对象,方便在模板中使用。 - 注意:
pinia
提供的storeToRefs
只会将数据做转换,而Vue
的toRefs
会转换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监听属性的区别
$subscribe()
监听整个 store 的变化watch()
更适合监听特定的状态片段$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}
})