pinia——打败vuex的新一代vue存储库
vue3已经发布很长一段时间了,vue官网也已经默认访问vue3的文档了。因此打算系系统统仔仔细细的学习一波~vue3系列文章将定期更新直至完结~ ~ ~使用官方提供的脚手架工具新建一个vue3项目会发现,官方已将pinia作为默认的状态存储库提供在安装选项中了。vuex的仓库中官方也有这么一段提示:大致是说:Pinia 现在是新的默认设置。Vue 的官方状态管理库已更改为Pinia。您可以简单地
🐝前言
vue3已经发布很长一段时间了,vue官网也已经默认访问vue3的文档了。因此打算系系统统仔仔细细的学习一波~ vue3系列文章将定期更新直至完结~ ~ ~
使用官方提供的脚手架工具新建一个vue3项目会发现,官方已将pinia作为默认的状态存储库提供在安装选项中了。
vuex的仓库中官方也有这么一段提示:
大致是说:Pinia 现在是新的默认设置。Vue 的官方状态管理库已更改为Pinia。您可以简单地将 Pinia 视为具有不同名称的 Vuex 5。Pinia 也适用于 Vue 2.x。Vuex 3 和 4 仍将被维护。但是,不太可能为其添加新功能。如果您打算开始一个新项目,我们强烈建议您使用 Pinia。
本文就来介绍打败vuex的新一代vue存储库Pinia究竟有和神奇魔法~
🍍Pinia介绍
u1s1,logo真可爱~
Pinia(发音为 /piːnjʌ/,类似于英语中的“peenya”)是最接近有效包名 piña(西班牙语中的_pineapple_)的词。 菠萝实际上是一组单独的花朵,它们结合在一起形成多个水果。 与 Store 类似,每一家都是独立诞生的,但最终都是相互联系的。 它也是一种美味的热带水果,原产于南美洲。
1. 创建一个Pinia store
- 安装pinia
npm install pinia
注意虽然pinia支持vue2.x和vue3.x,但是如果你的vue的版本低于2.7,还需要安装组合API:@vue/composition-api。
- 创建一个根存储并传递给应用程序
import { createApp } from 'vue'
import { createPinia } from 'pinia'
import App from './App.vue'
const app = createApp(App)
app.use(createPinia())
app.mount('#app')
如果你使用的是vue2,还需要安装一个插件并将创建的pinia注入应用程序的根目录
import { createPinia, PiniaVuePlugin } from 'pinia'
Vue.use(PiniaVuePlugin)
const pinia = createPinia()
new Vue({
el: '#app',
// 其他选项...
// ...
// 注意同一个 `pinia` 实例可以在多个 Vue 应用程序中使用
// 同一个页面
pinia,
})
- 定义一个store
export const useCounterStore = defineStore('counter', {
state: () => {
return {
count: 0,
msg: '开心',
todoList: ['吃饭', '绘画']
}
},
getters: {
doubleCount(state) {
return state.count * 2
}
},
actions: {
increment(payload?: number) {
this.count = payload ? this.count + payload : this.count + 1
}
}
})
2. 访问State
<template>
<div class="about">
<p>{{ counterStore.msg }}</p>
<p>{{ counterStore.count }}</p>
<p>{{ counterStore.doubleCount }}</p>
<p @click="() =>counterStore.increment(3)">点击我+1</p>
</div>
</template>
<script setup lang="ts">
import { storeToRefs } from 'pinia'
import { useCounterStore } from '@/stores/counter'
const counterStore = useCounterStore()
</script>
你也可以使用storeToRefs进行解构
<template>
<div class="about">
<p>{{ count }}</p>
<p>{{ msg }}</p>
<p>{{ doubleCount }}</p>
<ul>
<li v-for="(item, index) in todoList" :key="index">{{ item }}</li>
</ul>
</div>
</template>
<script setup lang="ts">
import { storeToRefs } from 'pinia'
import { useCounterStore } from '@/stores/counter'
const counterStore = useCounterStore()
// 也可以使用storeToRefs进行解构
let { count, doubleCount, msg, todoList } = storeToRefs(counterStore)
</script>
3. Pinia修改数据的四种方法
- 直接修改
counterStore.count++
- $patch
$patch 方法允许你使用部分“state”对象同时应用多个更改。
但是,使用这种语法应用某些突变非常困难或代价高昂:任何集合修改(例如,从数组中推送、删除、拼接元素)都需要创建一个新集合。
const newTodoList = [...counterStore.todoList, '睡午觉']
counterStore.$patch({
count: 100,
msg: '哈哈',
todoList: newTodoList
})
- $patch传递函数
$patch 方法也接受一个函数来批量修改集合内部分对象的情况
counterStore.$patch((state) => {
state.count = 100,
state.msg = '哈哈',
state.todoList.push('听音乐')
})
- action
当业务逻辑很复杂的时候,可以将方法写在store中的action里
actions: {
increment(payload?: number) {
this.count = payload ? this.count + payload : this.count + 1
}
}
4. 重置State
可以通过调用 store 上的 $reset() 方法将状态 重置 到其初始值
counterStore.$reset()
5. 替换state
通过将其 $state 属性设置为新对象来替换 Store 的整个状态
counterStore.$state = { counter: 666, msg: 'Paimon', todoList: [] }
也可以通过更改 pinia 实例的 state 来替换应用程序的整个状态。 这在 SSR for hydration 期间使用。
pinia.state.value = {}
6. 订阅状态
可以通过 store 的 $subscribe() 方法查看状态及其变化,类似于 Vuex 的 subscribe 方法。 与常规的 watch() 相比,使用 $subscribe() 的优点是 subscriptions 只会在 patches 之后触发一次。
counterStore.$subscribe((mutation, state) => {
// 每当它发生变化时,将整个状态持久化到本地存储
localStorage.setItem('cart', JSON.stringify(state))
})
7. Getters
- Getter 完全等同于 Store 状态的 计算值。 它们可以用 defineStore() 中的 getters 属性定义。 他们接收“状态”作为第一个参数以鼓励箭头函数的使用。
export const useCounterStore = defineStore('counter', {
state: () => {
return {
count: 0,
msg: '开心',
todoList: ['吃饭', '绘画']
}
},
getters: {
//自动将返回类型推断为数字
doubleCount(state) {
return state.count * 2
}
}
})
- 在getters中使用其他 getter:
getters: {
// 返回类型必须明确设置
doublePlusOne():number {
return this.doubleCount + 1
}
}
- 将参数传递给 getter:
getters: {
getUserById: (state) => {
return (userId) => state.users.find((user) => user.id === userId)
},
}
在组件中这样使用:
<template>
<p>User 2: {{ counterStore.getUserById(2) }}</p>
</template>
🆚与vuex比较
Pinia 最初是为了探索 Vuex 的下一次迭代会是什么样子,结合了 Vuex 5 核心团队讨论中的许多想法。最终,团队意识到 Pinia 已经实现了他们在 Vuex 5 中想要的大部分内容,并决定实现它。与 Vuex 相比,Pinia 提供了一个更简单的 API,具有更少的规范,提供了 Composition-API 风格的 API,最重要的是,在与 TypeScript 一起使用时具有可靠的类型推断支持。
- mutations 不再存在。他们经常被认为是 非常 冗长。他们最初带来了 devtools 集成,但这不再是问题。
- 无需创建自定义复杂包装器来支持 TypeScript,所有内容都是类型化的,并且 API 的设计方式尽可能利用 TS 类型推断。
- 不再需要注入、导入函数、调用函数、享受自动完成功能
- 无需动态添加 Store,默认情况下它们都是动态的,您甚至都不会注意到。请注意,您仍然可以随时手动使用 Store 进行注册,但因为它是自动的,您无需担心
- 不再有 modules 的嵌套结构。您仍然可以通过在另一个 Store 中导入和 使用 来隐式嵌套 Store,但 Pinia 通过设计提供平面结构,同时仍然支持 Store 之间的交叉组合方式。 您甚至可以拥有 Store 的循环依赖关系。
- 没有 命名空间模块。鉴于 Store 的扁平架构,“命名空间” Store 是其定义方式所固有的,您可以说所有 Store 都是命名空间的。
Pinia的优点
- 同时支持vue2与vue3
- 摒弃了mutations,只有state,getter,action
- Actions支持同步和异步
- 更符合Vue3的Composition api
- 天然支持ts
更多推荐
所有评论(0)