什么是 Pinia
如果你之前使用过 vuex 进行状态管理的话,那么 pinia 就是一个类似的插件。它是最新一代的轻量级状态管理插件。按照尤雨溪的说法,vuex 将不再接受新的功能,建议将 Pinia 用于新的项目。业界将其等同于最新vuex5.x版本(vuex4.x升级版本)
Pinia 优点
-
Pinia 没有 Mutations
-
Actions 支持同步和异步
-
没有模块的嵌套结构
Pinia 通过设计提供扁平结构,就是说每个 store 都是互相独立的,谁也不属于谁,也就是扁平化了,更好的代码分割且没有命名空间。 当然你也可以通过在一个模块中导入另一个模块来隐式嵌套 store,甚至可以拥有 store 的循环依赖关系
-
更好的 TypeScript 支持
不需要再创建自定义的复杂包装器来支持 TypeScript 所有内容都类型化, 并且 API 的设计方式也尽可能的使用 TS 类型推断
-
不需要注入、导入函数、调用它们,享受自动补全,让我们开发更加方便
-
无需手动添加 store,它的模块默认情况下创建就自动注册的
-
Vue2 和 Vue3 都支持
-
支持 Vue DevTools
Pinia 和 Vuex
Vuex: state 、Gettes 、 Mutations(同步)、Actions(异步)
Pinia:state .Gettes 、Actions(同步异步都支持)
Vuex当前最新版是4.x
- Vuex4用于Vue3
- Vuex3用于Vue2
Pinia当前最新版是2.x
- 即支持Vue2也支持Vue3
使用 Pinia
安装
yarn add pinia
# 或者使用 npm
npm install pinia
创建stores文件夹 index.ts
import { createPinia } from 'pinia'
//引入持久化插件
import piniaPluginPersist from 'pinia-plugin-persist'
const store = createPinia()
//使用存储插件
store.use(piniaPluginPersist)
export default store
main.ts 集成store
import { createApp } from 'vue'
import router from './router'
import store from '@/stores'
createApp(App).use(router).use(store).mount('#app')
持久化存储
- 安装持久化存储插件
- 集成插件
- 使用插件
//引入持久化插件
import piniaPluginPersist from 'pinia-plugin-persist'
//集成持久化存储插件
storeRoot.use(piniaPluginPersist)
//使用该插件,开启数据缓存
persist: {
//这里存储默认使用的是session
enabled: true,
strategies: [
{
// key的名称
key: 'userKey',
//更改默认存储,我更改为localstorage
storage: localstorage,
//可以选择哪些进入local存储,这样就不用全部都过
//默认是全部进去存存储进去
paths: ['list'],
},
],
},
定义模块与组件使用
stores 文件夹定义一个 store
Store 是使用 defineStore() 定义的,并且它需要一个唯一名称,作为第一个参数传递。defineStore 方法定义 store 返回一个函数第一个参数是应用程序中 store 的唯一 id。Pinia 使用用它将 store 连接到 devtools 第二个参数为选项对象,定义 state, actions,gettters, persist
import { defineStore } from 'pinia'
export const cartStore = defineStore('cart', {
state: () => {
return {
list: [
{ id: 1, name: 'JavaScript高级编程', price: 78.98 },
{ id: 2, name: 'Vue高级编程', price: 88.88 },
],
}
},
actions: {},
getters: {},
persost: {},
})
组件使用
import { cartStore } from '@/Store/cart'
const { list, addProduct } = cartSrore()
注意:
- 解构出来的状态失去响应式
- getters和state定义的名称不能相同
state 操作
state 是 store 的核心部分。 我们通常从定义应用程序的状态开始。在 Pinia 中,状态被定义为返回初始状态的函数
import { defineStore ] from "pinia"
const useStore = defineStore('storeld', {
//推荐使用完整炎型推断的箭头函数
state: () => {
return {
//所有这些医性都将自动推断其类型
counter: 0,
name: "Eduardo",
isAdmin: true,
}
},
})
访问 “state”
默认情况下,您可以通过store实例访问状态来直接读取和写入状态:
const store = useStore()
store. counter-
重置状态
您可以通过调用store 上的 $reset() 方法将状态重置到其初始值:
const store = useStore()
store.$reset()
改变状态
除了直接用store.counter++修改store,你还可以调用$patch方法。它允许您使用部分"state"对象同时应用多个更改:
store.$patch({
counter: store.counter + 1,
name: 'Abalam',
})
但是,使用这种语法应用某些突变非常困难或代价高昂:任何集合修改(例如,从数组中推送、删除、拼接元素)都需要您创建一个新集合。正因为如此,$patch方法也接受一个函数来批量修改集合内部分对象的情况:
cartStore.$patch((state) => {
state.items.push({ name: 'shoes', quantity: 1})
state.hasChanged = true
))
替换state
可以通过将其 $state 属性设置为新对象来替换 Store 的整个状态:
store.$state = { counter: 666, name: 'Paimon' ]
还可以通过更改 pinia 实例的state来替换应用程序的整个状态。这在SSR for hydration期间使用。
pinia.state.value = {}
订阅状态
可以通过store的 $subscribe()方法查看状态及其变化,类似于Vuex的 subscribe方法。与常规的watch()相比,使用$subscribe()的优点是subscriptions只会在patches 之后触发一次(例如,当使用上面的函数版本时)。
cartstore.$subscribe(( mutation,state) => {
//import{ MutationType } from 'pinia'
mutation.type // 'direct' / 'patch object' / 'patch function'
//与cartStore.$id相同
mutation.storeId // 'cart'
//适用于 mutation.type = 'patch object '
mutation.payload//补了对象传逃给to cartStore.$patch()
//每当它发生变化时,将整个状态持久化到本地存储
localStorage.setItem( 'cart', JSON.stringify(state))
})
默认情况下,staote subscriptions 绑定到添加它们的组件(如果store位于组件的 sotup()中),意思是,当组件被卸载时,它们将被自动删除。如果要在卸载组件后保留它们,请将{detached:true}作为第二个参数传递给detach当前组件的state subscription:
export default {
setup({
const somestore = useSomestore()
//此订阅将在组件卸戟后保密
someStore.$subscribe(callback, { detached: true }
//...
},
)
Getters
Getter 完全等同于 Store 状态的 计算值
Getter完全等同于Store状态的计算值。它们可以用defineStore()中的getters属性定义。他们接收"状态"作为第一个参数以鼓励箭头函数的使用:
export const usestore = definestore('main', {
state: () => {
counter: 0,
}),
getters: {
doubleCount: (state) => state.counter * 2.
},
})
将参数传递给 getter
Getters 只是幕后的computed属性,因此无法向它们传递任何参数。但是,您可以从getter返回一个函数以接受任何参数:
export const useStore = defineStore( 'main', {
getters: {
getUserById: (state) => {
return (userld) => state.users.find((user) => user.id = userId)
},
},
})
并在组件中使用:
<template>
<p>User 2: {{ getUserBy1d(2) }}</P>
</template>
<script>
export default {
setup() {
const store = useStore()
return { getUlserById: store.getUserById }
},
</script>
Actions
Actions 相当于组件中的 methods。 它们可以使用 defineStore() 中的 actions 属性定义,并且它们非常适合定义业务逻辑:
export const useStore = defineStore( 'main', ({
state: () => {
counter: 0,
}),
actions: {
increment () {
this.counter++
},
randomi zecounter() {
this.counter = Math.round(100 * Math.random())
},
},
})