1. 概述
- Pinia本质上依然是一个状态管理的库,用于跨组件、页面进行状态共享(这点和Vuex、Redux一样);
- 与 Vuex 相比,Pinia 提供了一个更简单的 API,具有更少的仪式,提供了 Composition-API 风格的 API;
- 最重要的是,在与 TypeScript 一起使用时具有可靠的类型推断支持。
2. 和Vuex相比,Pinia的优势
- 比如mutations不再存在:他们经常被认为是非常冗长;他们最初带来了 devtools 集成,但这不再是问题;
- 更友好的TypeScript支持,Vuex之前对TS的支持很不友好;
- 不再有modules的嵌套结构:你可以灵活使用每一个store,它们是通过扁平化的方式来相互使用的;
- 也不再有命名空间的概念,不需要记住它们的复杂关系。
3. Pinia的使用
- 安装
yarn add pinia
# 或者使用 npm
npm install pinia
- 创建一个pinia并且将其传递给应用程序
import { createPinia } from 'pinia'
const pinia = createPinia()
export default pinia
- 使用
import pinia from './stores'
createApp(App).use(pinia).mount('#app')
4. 认识Store
- 一个 Store (如 Pinia)是一个实体,它持有绑定到组件树的状态和业务逻辑,也就是保存了全局的状态;始终存在,且每个人都可以读取和写入的组件;可以在应用程序中定义任意数量的Store来管理状态。
- 三个核心概念 state、getters、actions;等同于组件的data、computed、methods;一旦 store 被实例化,就可以直接在 store 上访问 state、getters 和 actions 中定义的任何属性。
(1)定义一个Store
- Store 使用
defineStore()定义; - 且它需要一个唯一名称,作为第一个参数传递:这个 name,也称为 id,是必要的,Pinia 使用它来将 store 连接到 devtools;
- 返回的函数统一使用useX作为命名方案,这是约定的规范。
import { defineStore } from 'pinia'
const useCounter = defineStore("counter", {
...
})
export default useCounter
(2)使用定义的Store
- Store在它被使用之前是不会创建的,可以通过调用use函数来使用Store。
<template>
<div class="home">
<h2>count: {{ counterStore.count }}</h2>
</div>
</template>
<script setup>
import useCounter from '@/stores/counter';
const counterStore = useCounter()
</script>
- 注意Store获取到后不能被解构,那么会失去响应式。为了从 Store 中提取属性同时保持其响应式,要使用storeToRefs()。
import { toRefs } from 'vue'
import { storeToRefs } from 'pinia'
const { count } = toRefs(counterStore)
const { count } = storeToRefs(counterStore)
4.1 State
(1)认识和定义State
- state 是 store 的核心部分,因为store是用来帮助我们管理状态的。在Pinia中,状态被定义为返回初始状态的函数。
state: () => ({
count: 99,
friends: [
{ id: 1, name: "a" },
{ id: 2, name: "b" },
]
}),
(2)操作State
- 读取和写入 state:默认情况下,可以通过 store 实例访问状态来直接读取和写入状态。
function incrementCount() {
counterStore.count++
}
- 重置 State:可以通过调用 store 上的
$reset()方法将状态重置到其初始值。
function resetState() {
userStore.$reset()
}
- 改变State:可以调用
$patch方法;使用部分“state”对象同时应用多个更改。
// 1.一个个修改状态
userStore.name = "kobe"
userStore.age = 20
// 2.一次性修改多个状态
userStore.$patch({
name: "abab",
age: 23
})
- 替换State:可以通过将其
$state属性设置为新对象来替换Store 的整个状态。
userStore.$state = {
name: "cdcd",
age: 24
}
4.2 Getters
- Getters相当于Store的计算属性:用 defineStore() 中的 getters 属性定义。getters中可以定义接受一个state作为参数的函数。
import useUser from './user'
getters: {
// 1.基本使用
doubleCount(state) {
return state.count * 2
},
// 2.一个getter引入另外一个getter
doubleCountAddOne() {
// this是store实例
return this.doubleCount + 1
},
// 3.getters也支持返回一个函数
getFriendById(state) {
return function(id) {
for (let i = 0; i < state.friends.length; i++) {
const friend = state.friends[i]
if (friend.id === id) {
return friend
}
}
}
},
// 4.getters中用到别的store中的数据
showMessage(state) {
// 1.获取user信息
const userStore = useUser()
// 2.获取自己的信息
// 3.拼接信息
return `name:${userStore.name}-count:${state.count}`
}
},
4.3 Actions
- Actions 相当于组件中的 methods。可以使用 defineStore() 中的 actions 属性定义,并且它们非常适合定义业务逻辑。和getters一样,在action中可以通过this访问整个store实例的所有操作;
actions: {
increment() {
this.count++
},
incrementNum(num) {
this.count += num
}
}
- 并且Actions中是支持异步操作的,可以编写异步函数,在函数中使用await。
actions: {
async fetchHomeMultidata() {
const res = await fetch("https://pinia.web3doc.top/introduction.html")
const data = await res.json()
return data
}
<script setup>
import useHome from '@/stores/home';
const homeStore = useHome()
homeStore.fetchHomeMultidata().then(res => {
console.log("fetchHomeMultidata的action已经完成了:", res)
})
</script>