前言
Pinia和Vuex有很多相似之处,它们都是用于实现状态管理的插件。但是,Pinia相对于Vuex来说,更加轻量,并且提供了更多的功能,例如支持异步状态更新、更好的调试能力等🍍🥭🍎。
一、🍍什么是Pinia
Pinia是Vue的专属的最新状态管理库,是Vuex状态管理工具的替代品
优势:
- 提供了更加简单的API(去掉了mutation)
- 提供符合组合式风格的API(和Vue3新语法统一)
- 去掉modules的概念,每一个store都是独立的模块
- 搭配TypeScript一起使用提供可靠的类型推断
1. 创建Vue空项目
shell
npm init vue@latest
使用VScode打开项目,并安装依赖,然后运行项目
shell
cd vue-pinia
npm install
npm run dev
项目创建完成
2. 安装Pinia
shell
npm install pinia
3. 将Pinia挂载到vue项目中
main.js
js
import './assets/main.css'
import { createApp } from 'vue'
import App from './App.vue'
//1. 导入createPinia
import {createPinia} from 'pinia'
//2. 执行方法得到实例
const pinia=createPinia()
//3. 将pinia实例加入到app中
createApp(App).use(pinia).mount('#app')
Pinia在vue中是以插件的形式存在。
二、🥞Pinia基础使用
1. 官网案例
核心步骤:
-
定义Store
stores/counter.js
jsimport { defineStore } from 'pinia' import { ref } from 'vue' export const useCounterStore = defineStore('counter', () => { //数据(state) const count = ref(0) //定义修改数据的方法(action 同步+异步) const increment = () => { count.value++ } //以对象的形式返回 return { count, increment } })
官方提示:
-
你可以对 defineStore()的返回值进行任意命名,但最好使用 store 的名字,同时以 use开头且以 Store结尾。(比如 useUserStore,useCartStore,useProductStore)
-
第一个参数是你的应用中 Store 的唯一 ID。
-
defineStore()
的第二个参数可接受两类值:Setup 函数或 Option 对象。
-
-
在组件中使用store
App.vue
js<script setup> //1. 引入方法 import {useCounterStore} from '@/stores/counter' //2. 执行方法得到store实例 const counterStore=useCounterStore() console.log(counterStore); </script> <template> <button @click="counterStore.increment">{{counterStore.count}}</button> </template>
2. getter实现
Pinia中的getters直接使用computed函数进行模拟。
Getter 完全等同于 store 的 state 的计算值。可以通过 defineStore() 中的 getters属性来定义它们。推荐使用箭头函数,并且它将接收 state作为第一个参数.
stores/counter.js
js
import {defineStore} from 'pinia'
import {computed, ref} from 'vue'
export const useCounterStore = defineStore('counter', () => {
//数据(state)
const count = ref(0)
//定义修改数据的方法
const increment = () => {
count.value++
}
//定义getter
const doubleCount = computed(() => count.value * 2)
//以对象的形式返回
return {count, increment, doubleCount}
})
App.vue
js
<script setup>
//引入方法
import {useCounterStore} from '@/stores/counter'
//执行方法得到store实例
const counterStore=useCounterStore()
console.log(counterStore);
</script>
<template>
<button @click="counterStore.increment">{{counterStore.count}}</button><br>
<div>这是刚刚定义的doubleCount:{{ counterStore.doubleCount}}</div>
</template>
大多数时候,getter 仅依赖 state,不过,有时它们也可能会使用其他 getter。因此,即使在使用常规函数定义 getter 时,我们也可以通过 this访问到整个 store 实例,但(在 TypeScript 中)必须定义返回类型。这是为了避免 TypeScript 的已知缺陷,不过这不影响用箭头函数定义的 getter,也不会影响不使用 this 的 getter。
3. action如何异步实现
action中实现异步和组件中定义数据和方法的风格完全一致
先安装axios
shell
npm install axios
stores/counter.js
此处创建了一个异步的action用来请求一个列表数据,和一个响应式的列表用来存储数据(我把之前的内容删掉了,以免产生误导,还是原来的两个文件)
js
import {defineStore} from 'pinia'
import {computed, ref} from 'vue'
import axios from "axios";
export const useCounterStore = defineStore('counter', () => {
//定义一个异步action
const list = ref([])
const getList = async () => {
//此接口已经失效,无法发起请求,只能模拟一下数据,意思意思
// const response = await axios.get("http://geek.itheima.net/y1_0/channels")
// response.data.data.channels返回的就是一个列表,下面用模拟数据演示
// list.value = response.data.data.channels
list.value = ['模拟数据1', '模拟数据2', '模拟数据3', '模拟数据4', '模拟数据5', '模拟数据6']
}
//以对象的形式返回
return {list, getList}
})
App.vue
js
<script setup>
import {useCounterStore} from '@/stores/counter'
import {onMounted} from "vue";
const counterStore = useCounterStore()
console.log(counterStore);
onMounted(() => {
counterStore.getList()
})
</script>
<template>
<ul>
<li v-for="item in counterStore.list" >{{item}}</li>
</ul>
</template>
注意:此处把axios的请求注释掉完全是无奈之举,不注释掉会报错,导致模拟数据也无法渲染
4. storeToRefs函数
使用storeToRefs函数可以辅助保持数据 (state + getter) 的响应式解构
错误示范:直接解构赋值(响应式丢失)
js
<script setup>
import {useCounterStore} from '@/stores/counter'
const counterStore = useCounterStore()
//直接解构赋值
const {count, doubleCount} = useCounterStore()
</script>
<template>
<button @click="counterStore.increment">{{ count }}</button>
<br>
<div>这是刚刚定义的doubleCount:{{ doubleCount }}</div>
</template>
App.vue
加上storeToRefs()
js
<script setup>
import {useCounterStore} from '@/stores/counter'
//引入storeToRefs
import {storeToRefs} from "pinia";
const counterStore = useCounterStore()
//方法包裹(保持响应式更新)
const {count, doubleCount} =storeToRefs(useCounterStore())
</script>
<template>
<button @click="counterStore.increment">{{ count }}</button>
<br>
<div>这是刚刚定义的doubleCount:{{ doubleCount }}</div>
</template>
数据正常响应
打印前后两次解构出来的值,使用过storeToRefs后解构出来的才是响应式的数据
注意:storeToRefs只负责数据的解构,方法无法通过其解构,如果要解构方法,只需要从原本的store对象中解构即可
js
const {increment} =counterStore
5. 调试Pinia
总结
本文很简单的介绍了Pinia的使用,对于需要快速开发但又从未接触过Pinia的朋友极其友好,如果喜欢的话望收藏,点赞,有不足之处还望能够在评论区指出。