1.介绍
- Pinia 是 Vue 的专属状态管理库,它允许你跨组件或页面共享状态,用来代替vuex
- 与vuex区别:vuex只有一个store,所有的数据都挂载在其上面,而Pinia是一个管理库,既然是库就可以定义多个store,每个store可单独引入
2.安装Pinia
- 引入pinia
- 实例化:createPinia()
- 执行安装:app.use()
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
import router from './router'
const app = createApp(App)
app.use(createPinia())
app.use(router)
app.mount('#app')
3.定义store
- 支持定义多个store,以此对数据类型分类,推荐一个文件一个store
- 每个store包含3个部分:state,getter,action
//store/counter.js
import { ref, computed } from 'vue'
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('counter', () => {
const count = ref(1)
const doubleCount = computed(() => count.value * 2)
function increment() {
count.value++
}
return { count, doubleCount, increment }
})
4.读取store
- 引入并读取store,可直接修改state,也可以通过action来修改
- 一个store会被多次引入,store 的 Setup 函数只有在useXXXStore()方法执行时才会运行,且只会运行一次,之后以缓存的形式存在,保证每次引用时数据不会重置的同时各个组件间还能共享这个store的数据
<script setup lang="ts">
import { useCounterStore } from '@/stores/counter'
const store = useCounterStore()
</script>
<template>
<main>
<div>
<button @click="store.count++">{{ store.count }}</button>
</div>
<div>
<button @click="store.increment()">{{ store.count }}</button>
</div>
<h2>{{ store.doubleCount }}</h2>
</main>
</template>
5.从 Store 解构
- 每个store是一个具有响应式特性proxy对象,所以当它的属性和html模版绑定时,模板会随着数据的更新而更新
- 但是对 Store 解构时,其属性值时一个非响应式的数据,此时不能将其绑定到页面中,这些失去了这个数据的意义,所以不能直接对其进行解构赋值
- pinia的storeToRefs()可以对store进行转换,将Store的属性转换成ref对象,再包装成对象返回,所以此时解构赋值是可行的
- 通过storeToRefs()解构赋值的数据和Store的属性指向同一个数据,改变其中的一个,另外一个会受影响
<script setup lang="ts">
import { storeToRefs} from 'pinia'
import { useCounterStore } from '@/stores/counter'
const store = useCounterStore()
const { count } = storeToRefs(store)
console.log('storeToRefs',storeToRefs(store))
console.log('store',store)
</script>
<template>
<main>
<div>
<button @click="count++">{{ count }}</button>
</div>
<div>
<button @click="store.count++">{{ store.count }}</button>
</div>
</main>
</template>
6.组合式Store
- 解析官方案例:为什么store 相互使用时,不能直接在 setup 函数中直接互相读取对方的 state
import { ref } from 'vue'
import { defineStore } from 'pinia'
export const useX = defineStore('x', () => {
console.log('useX setup')
const y = useY()
console.log('useX steup y.name', y.name)
function doSomething() {
// ✅ 读取 computed 或 action 中的 y 属性
const yName = y.name
// ...
}
console.log('useX setup after')
return {
name: ref('I am X'),
}
})
export const useY = defineStore('y', () => {
console.log('useY setup')
const x = useX()
//此时useX的setup还未执行完毕,没有return,拿不到其name
console.log('useY steup x.name', x.name)
function doSomething() {
// ✅ 读取 computed 或 action 中的 x 属性
const xName = x.name
// ...
}
console.log('useY setup after')
return {
name: ref('I am Y'),
}
})
<script setup lang="ts">
import { useX, useY } from '@/stores/some'
var storeX = useX()
</script>