文章目录
- 1.pinia的介绍
- 2.pinia的配置
- 3.state状态管理
- 3.1 state的基本使用
- 3.2 state的访问
- 4.getters
1.pinia的介绍
Pinia 是 Vue 的专属状态管理库,它允许你跨组件或页面共享状态。如果你熟悉组合式 API 的话,你可能会认为可以通过一行简单的 export const state = reactive({}) 来共享一个全局状态。
与 Vuex 相比,Pinia 不仅提供了一个更简单的 API,也提供了符合组合式 API 风格的 API,最重要的是,搭配 TypeScript 一起使用时有非常可靠的类型推断支持。
Vuex 3.x 只适配 Vue 2,而 Vuex 4.x 是适配 Vue 3 的。
- mutation 已被弃用。它们经常被认为是极其冗余的。它们初衷是带来 devtools 的集成方案,但这已不再是一个问题了。
- 无需要创建自定义的复杂包装器来支持 TypeScript,一切都可标注类型,API 的设计方式是尽可能地利用 TS 类型推理。
- 无过多的魔法字符串注入,只需要导入函数并调用它们,然后享受自动补全的乐趣就好。
- 无需要动态添加 Store,它们默认都是动态的,甚至你可能都不会注意到这点。注意,你仍然可以在任何时候手动使用一个 Store 来注册它,但因为它是自动的,所以你不需要担心它。
- 不再有嵌套结构的模块。你仍然可以通过导入和使用另一个 Store 来隐含地嵌套 stores 空间,虽然是 Pinia 从设计上提供的是一个扁平的结构,但仍然能够在 Store 之间进行交叉组合。你甚至可以让 Stores 有循环依赖关系。
- 不再有可命名的模块。考虑到 Store 的扁平架构,Store 的命名取决于它们的定义方式,你甚至可以说所有 Store 都应该命名。
2.pinia的配置
yarn add pinia
# 或者使用 npm
npm install pinia
main.js
import { createApp } from 'vue'
import { createPinia } from 'pinia' // 引入pinia
import App from './App.vue'const pinia = createPinia() // 创建实例
const app = createApp(App)app.use(pinia) // 安装插件
app.mount('#app')
3.state状态管理
Store (如 Pinia) 是一个保存状态和业务逻辑的实体,它并不与你的组件树绑定。换句话说,它承载着全局状态。它有点像一个永远存在的组件,每个组件都可以读取和写入它。它有三个概念,state、getter 和 action,我们可以假设这些概念相当于组件中的 data、 computed 和 methods。
3.1 state的基本使用
src/store/counter.js
1.Option Store:与 Vue 的选项式 API 类似,我们也可以传入一个带有 state、actions 与 getters 属性的 Option 对象
import { defineStore } from 'pinia'// 你可以对 `defineStore()` 的返回值进行任意命名,但最好使用 store 的名字,
// 同时以 `use` 开头且以 `Store` 结尾。(比如 `useUserStore`,`useCartStore`,`useProductStore`)
// 第一个参数是你的应用中 Store 的唯一 ID。
export const useStore = defineStore('main', {state: () => ({ count: 0 }),getters: {double: (state) => state.count * 2,},actions: {increment() {this.count++},},
})
2.Setup Store:也存在另一种定义 store 的可用语法。与 Vue 组合式 API 的 setup 函数 相似,我们可以传入一个函数,该函数定义了一些响应式属性和方法,并且返回一个带有我们想暴露出去的属性和方法的对象。
import { defineStore } from 'pinia'
import { computed, ref } from 'vue'export const useCounterStore = defineStore('counter', () => {// stateconst count = ref(0)// gettersconst double = computed(() => count.value * 2)// actionsfunction increment () {count.value++}return { count, double, increment }
})
src/App.vue
<template><div><h1>我是app</h1>{{ counter.count }}{{ count }}</div>
</template><script setup>
import { useCounterStore } from '@/stores'
import { storeToRefs } from 'pinia'
const counter = useCounterStore()// ❌ 这将无法生效,因为它破坏了响应性
// 这与从 `props` 中解构是一样的。
const { count, double } = counter// `name` and `doubleCount` 都是响应式 refs
// 这也将为由插件添加的属性创建 refs
// 同时会跳过任何 action 或非响应式(非 ref/响应式)属性
const { count, double } = storeToRefs(counter)
// 名为 increment 的 action 可以直接提取
const { increment } = counter</script>
3.2 state的访问
得到state的值。
import { useCounterStore } from './store/counter' // 导入创建好的counter.js
const counter = useCounterStore() // 实例化console.log(counter.count) // 0import { useCounterStore } from './store/counter' // 导入创建好的counter.js
const counter = useCounterStore() // 实例化console.log(counter.count) // 0
store 的 $reset() 方法将 state 重置为初始值。
import { useCounterStore } from './store/counter' // 导入创建好的counter.js
const counter = useCounterStore() // 实例化counter.$reset() // store 的 $reset() 方法将 state 重置为初始值。
修改state的4种方法。
<script setup>
import { useCounterStore } from './store/counter'
const counter = useCounterStore()// 方式1
counter.count++//以下两种方式可以一次性修改多个值// 方式2: $patch 对象写法
counter.$patch({count: counter.count + 1,
})// 方式3: $patch 函数写法
counter.$patch((state) => {// state 是 counter里的statestate.count = state.count + 1
})// 方式4: 通过 actions 创建的函数修改
counter.increment()</script>
$subscribe对state的订阅。
<script setup>
import { useCounterStore } from './store/counter'
const counter = useCounterStore()// 必须先订阅在修改才会触发
counter.$subscribe((mutation, state) => {console.log(mutation)console.log(state)/*** 其中 state 是 mainStore 实例,* 而 mutation mutation对象主要包含三个属性events : 是这次state改变的具体数据,包括改变前的值和改变后的值等等数据storeId :是当前store的idtype:type表示这次变化是通过什么产生的,主要有三个分别是“direct” :通过 action 变化的”patch object“ :通过 $patch 传递对象的方式改变的“patch function” :通过 $patch 传递函数的方式改变的*/// 每当状态发生变化时,将整个 state 持久化到本地存储。localStorage.setItem('counter', JSON.stringify(state))
})// 修改state值
counter.increment()</script>
4.getters
export const useCounterStore = defineStore('Counter',{state: () => {return {name: '快乐超人',}},getters: {formatName: (state) => {return state.name + '00';},},
})
import { useCounterStore } from './store/counter'
const counter = useCounterStore()counter.formatName //快乐超人00import { useCounterStore } from './store/counter'
const counter = useCounterStore()counter.formatName //快乐超人00
getters传入参数。
export const useCounterStore = defineStore('Counter', {getters: {getUserById: (state) => {return (userId) => state.users.find((user) => user.id === userId)},},
})
import { useCounterStore } from './store/counter'
const counter = useCounterStore()counter.getUserById(2)