什么是pinia
Pinia 是 Vue 的专属状态管理库,可以实现跨组件或页面共享状态,是 vuex 状态管理工具的替代品,和 Vuex相比,具备以下优势
- 提供更加简单的API (去掉了 mutation )
- 提供符合组合式API风格的API (和 Vue3 新语法统一)
- 去掉了modules的概念,每一个store都是一个独立的模块
- 搭配 TypeScript 一起使用提供可靠的类型推断
通俗理解: 我们可以认为Pinia 是一个共享储物柜,专门帮你解决Vue项目中组件之间 数据相互拿不到或数据不同步的烦恼
举个栗子🌰:
- 场景: 你做了一个电商网站,用户头像和昵称(比如“小明”)需要在导航栏、个人主页、侧边栏等多个地方显示。如果用传统方法,每个组件都要单独传值,麻烦得要死!
- 用 Pinia 后:
- 建一个叫
userStore 的储物柜,把用户数据(小明的信息)存进去。
- 导航栏、个人主页、侧边栏这些组件 直接去储物柜里拿数据,不用层层传递。
- 如果小明修改了昵称,储物柜里的数据自动更新,所有用到的地方立刻同步!
通俗总结它的用处:
- 共享数据:像购物车、用户信息这类多个页面都要用的数据,不用再靠组件之间“互相传纸条”。
- 自动同步:数据一变,所有用到的地方自动更新(比如购物车数量实时变化)。
- 代码清爽:把零散在各处的数据集中放到“储物柜”,好维护、好找bug。
再举个生活化例子:
想象全家共用一台智能冰箱(Pinia):
- 妈妈买了苹果(修改数据),所有人打开冰箱都能看到(自动同步)。
- 不用挨个打电话通知:“冰箱有苹果啦!”(省掉 props 传值)。
- 爸爸想吃香蕉,直接往冰箱里加(任何组件都能改数据)。
这就是 Pinia 的作用——让数据共享变简单,告别繁琐传值! 🚀
创建空Vue项目并安装Pinia
1. 创建空Vue项目
2. 安装Pinia并注册
1 2 3 4 5 6 7 8
| import { createPinia } from 'pinia'
const app = createApp(App)
app.use(createPinia()) app.use(router) app.mount('#app')
|
实现counter
核心步骤: 官方文档 stores目录下新建一个counter.js
- 定义store
- 组件使用store
1- 定义store
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
| import { defineStore } from 'pinia' import { ref } from 'vue'
export const useCounterStore = defineStore('counter', ()=>{ const count = ref(0)
const increment = ()=>{ count.value++ }
return { count, increment } })
|
2- 组件使用store
App.vue
1 2 3 4 5 6 7 8 9 10 11 12
| <script setup> // 1. 导入use方法 import { useCounterStore } from '@/stores/counter' // 2. 执行方法得到store store里有数据和方法 const counterStore = useCounterStore() </script>
<template> <button @click="counterStore.increment"> {{ counterStore.count }} </button> </template>
|
实现getters
getters直接使用计算属性computed函数进行模拟即可实现
1 2 3 4
| const count = ref(0)
const doubleCount = computed(() => count.value * 2)
|
异步action
思想:action函数既支持同步也支持异步,和在组件中发送网络请求写法保持一致
步骤:
- store中定义action
- 组件中触发action
1- store中定义action
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| const API_URL = 'http://geek.itheima.net/v1_0/channels'
export const useCounterStore = defineStore('counter', ()=>{ const list = ref([]) const loadList = async ()=>{ const res = await axios.get(API_URL) list.value = res.data.data.channels } return { list, loadList } })
|
2- 组件中调用action
1 2 3 4 5 6 7 8 9 10 11 12
| <script setup> import { useCounterStore } from '@/stores/counter' const counterStore = useCounterStore() // 调用异步action counterStore.loadList() </script>
<template> <ul> <li v-for="item in counterStore.list" :key="item.id">{{ item.name }}</li> </ul> </template>
|
storeToRefs保持响应式解构
直接基于store进行解构赋值,响应式数据(state和getter)会丢失响应式特性,使用storeToRefs辅助保持响应式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16
| <script setup> import { storeToRefs } from 'pinia' import { useCounterStore } from '@/stores/counter' const counterStore = useCounterStore() // 使用它storeToRefs包裹之后解构保持响应式 store getter const { count } = storeToRefs(counterStore)
const { increment } = counterStore </script>
<template> <button @click="increment"> {{ count }} </button> </template>
|