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