Pinia进阶:优雅的setup(函数式)写法+封装到你的企业项目 - 腾讯云开发者社区-腾讯云 (tencent.com)
一文搞懂pinia状态管理(保姆级教程) - 知乎 (zhihu.com)
Pinia | The intuitive store for Vue.js (vuejs.org)
pinia - 旺仔米苏的专栏 - 掘金 (juejin.cn)
三大概念
在了解三大概念之前,需要了解什么是store,按照官方的解释:
Store (如 Pinia) 是一个保存状态和业务逻辑的实体,它并不与你的组件树绑定。换句话说,它承载着全局状态。它有点像一个永远存在的组件,每个组件都可以读取和写入它。它有三个概念,state、getter 和 action,我们可以假设这些概念相当于组件中的
data、computed和methods。
可以这样理解的:store是实际存储数据的地方,其中state中存储着数据,因为state中存储着最原始的数据,而我们想要从这些数据过滤出一部分我们自己需要的数据的话,就需要使用到getter,getter可以对state中的数据进行处理,而action则是,可以对state中的数据进行修改
在vue项目中使用pinia
这里是使用的vite创建的项目,只需要修改
main.js就可以了
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import './style.css'
import App from './App.vue'
const pinia = createPinia()
const app = createApp(App)
app.use(pinia)
app.mount('#app')创建store
你可以定义任意多的 store,但为了让使用 pinia 的益处最大化(比如允许构建工具自动进行代码分割以及 TypeScript 推断),你应该在不同的文件中去定义 store。所以在src目录下创建一个stores的目录,用来存放store

可以在stores中创建多个store,然后从其他的文件进行引用
选项式的写法
// 引入defineStore
import {defineStore} from 'pinia'
// 你可以对 `defineStore()` 的返回值进行任意命名,但最好使用 store 的名字,同时以 `use` 开头且以 `Store` 结尾。(比如 `useUserStore`,`useCartStore`,`useProductStore`),这个规则最好遵守
// 第一个参数是你的应用中 Store 的唯一 ID。
//
export const useTestStore = defineStore('test', {
// 官方在这里建议使用箭头函数
state: () => {
return {
count: 5
}
},
// 这里可以写很多个这样的函数,可以使用箭头函数,也可以使用function关键字进行定义
getters: {
//double: (state) => state.count * 2
// double: function (state) {
// return state.count * 2
// }
double(state) {
return state.count * 2
}
},
//和上面一样,上面可以定义的,这里也可以
actions: {
increment() {
this.count++
},
deduce() {
this.count--
},
}
})setup写法
这里的defineStore的第二个参数为一个箭头函数
import {defineStore} from "pinia";
import {computed, ref} from "vue";
export const test2 = defineStore('test2', () => {
const count = ref(0) //这相当于上面的state
function increment() { //相当于上面的action,可以对数据进行修改,可以定义多个函数
count.value--
}
function deduce() {
count.value--
}
const double = computed(() => { //相当于上面的getter
return count * 2
})
return {count, increment , reduce , double} //在定义完成之后,需要将数据进行返回
}
)上面的代码表示创建一个id为test2的store,包含一个名为count的state,和一个名为increment和一个名为deduce的action,还有一个double的getter
使用
store的定义
import {defineStore} from "pinia";
import {computed, ref} from "vue";
export const test2 = defineStore('test2', () => {
const count = ref()
function increment() {
count.value++
}
function deduce() {
count.value--
}
const double = computed(() => {
return count.value * 2
})
return {count, increment, deduce, double}
}
)通过setup的语法进行定义,在使用时,我觉得更加流畅
store访问state数据
在我看来pinia像这样使用,非常的符合逻辑,用起来非常顺畅
<template>
<!--直接使用store进行对state进行引用-->
<h3>{{ test.count }}</h3>
<!--使用store直接对getter进行引用,不需要额外的操作-->
<h3>double: {{ test.double }}</h3>
<!--使用store直接调用action-->
<button type="button" @click="test.increment(1)">点我加一</button>
<button type="button" @click="test.deduce(1)">点我减一</button>
</template>
<script setup>
import {useTestStore} from "../stores/Test.js";
const test = useTestStore()
</script>
<style scoped>
</style>使用解构的方式进行访问数据
如果state如果是普通数据类型,例如字符,数字等,那么在解构之后,就不会是响应式的变量,如果state是引用类型的话,那么结构出来的state是响应式,如果需要将普通数据类型变为响应式变量,需要使用
storeToRefs进行转换
<template>
<!--
这里使用使用结构出来的变量,这里的count不是响应式的,下面的按钮无法对这个count进行改变
-->
<h3>{{ count }}</h3>
<h3>double: {{ double }}</h3>
<!--和之前在store调用一样的效果-->
<button type="button" @click="increment(1)">点我加一</button>
<button type="button" @click="deduce(1)">点我减一</button>
</template>
<script setup>
import {useTestStore} from "../stores/Test.js";
const test = useTestStore()
const {count, double, increment, deduce} = test
</script>
<style scoped>
</style>使用storeToRefs
注意,在使用storeToRefs时,需要将getter从中解构出来,不然,getter不会是响应式的,而action,无法从中解构出
<template>
<!--
这里使用使用结构出来的变量
-->
<h3>{{ count }}</h3>
<h3>double: {{ double }}</h3>
<!--和之前在store调用一样的效果-->
<button type="button" @click="increment(1)">点我加一</button>
<button type="button" @click="deduce(1)">点我减一</button>
</template>
<script setup>
import {useTestStore} from "../stores/Test.js";
import {storeToRefs} from "pinia";
const test = useTestStore()
// 这是错误的写法,action无法从storeToRefs解构出,写了之后,得出的结果为undefine
// const {count, double, increment, deduce} = storeToRefs(test)
const {count, double} = storeToRefs(test)
const {increment, deduce} = test
</script>
<style scoped>
</style>使用computed给普通变量响应式
上面提到,当应用的变量是简单数据类型,在解构时需要使用
storeToRefs,可以使用computed将其包裹,将其返回,在使用时,直接使用这个变量(isLogin),这个变量就是响应式的
import {defineStore} from 'pinia'
import {computed, ref} from "vue"
export const useLoginStore = defineStore('login', () => {
const login = ref(false);
const isLogin = computed(() => {
return login
})
function setLogin(bool) {
login.value = bool
}
return {isLogin, setLogin}
})