Pinia(Vue 的专属状态管理库)

什么是Pinia

Pinia 起始于 2019 年 11 月左右的一次实验,其目的是设计一个拥有组合式 API 的 Vue 状态管理库

为什么选择Pinia

在pinia没有出现以前,我们都在使用vuex来进行状态管理,而pinia起源于一次探索 Vuex 下一个迭代的实验,因此结合了 Vuex 5 核心团队讨论中的许多想法。最后,我们意识到 Pinia 已经实现了我们在 Vuex 5 中想要的大部分功能,所以决定将其作为新的推荐方案来代替 Vuex。

使用Pinia的好处

  • mutation 已被弃用,只有 state getters actions
  • 更加支持TS语法
  • 也提供了符合组合式 API 风格的 API
  • actions支持同步与异步
  • vue开发者工具支持pinia
  • 能够构建多个stores
  • 轻量

使用

使用包管理工具

yarn add pinia
# 或者使用 npm
npm install pinia

在main.js注册

import {
    
     createApp } from 'vue'
import {
    
     createPinia } from 'pinia'
import App from './App.vue'

const pinia = createPinia()
const app = createApp(App)

app.use(pinia)
app.mount('#app')

创建仓库

import {
    
    defineStore} from 'pinia';
export default defineStore("main",{
    
    
    state:()=>{
    
    
        return{
    
    
            count:10
        }
    }
})

在vue中使用

<template>
  <div>
    商品数量:{
   
   { store.count }}
  </div>
</template>
<script setup>
import useMainStore from './store/index'
const store = useMainStore()
</script>

渲染结果

在这里插入图片描述

核心概念

state

export default defineStore("main",{
    
    
    state:()=>{
    
    
        return{
    
    
            count:10
        }
    }
})

其中main是store的独一无二的名字,这个名字 ,也被用作 id ,是必须传入的, Pinia 将用它来连接 store 和 devtools。为了养成习惯性的用法,将返回的函数命名为 use… 是一个符合组合式函数风格的约定。

defineStore() 的第二个参数可接受两类值:Setup 函数或 Option 对象。

Option Store

与 Vue 的选项式 API 类似,我们也可以传入一个带有 state、actions 与 getters 属性的 Option 对象

export const useCounterStore = defineStore('counter', {
    
    
  state: () => ({
    
     count: 0 }),
  getters: {
    
    
    double: (state) => state.count * 2,
  },
  actions: {
    
    
    increment() {
    
    
      this.count++
    },
  },
})

Setup Store

也存在另一种定义 store 的可用语法。与 Vue 组合式 API 的 setup 函数 相似,我们可以传入一个函数,该函数定义了一些响应式属性和方法,并且返回一个带有我们想暴露出去的属性和方法的对象。

export const useCounterStore = defineStore('counter', () => {
    
    
  const count = ref(0)
  function increment() {
    
    
    count.value++
  }

  return {
    
     count, increment }
})

state 是 store 的数据 (data),getters 是 store 的计算属性 (computed),而 actions 则是方法 (methods)。

使用store

<script setup>
import {
    
     useCounterStore } from '@/stores/counter'
// 可以在组件中的任意位置访问 `store` 变量 ✨
const store = useCounterStore()
</script>

为了养成习惯性的用法,将返回的函数命名为 use…

<script setup>
import {
    
     storeToRefs } from 'pinia'
const store = useCounterStore()
const {
    
     name, doubleCount } = storeToRefs(store)
const {
    
     increment } = store
</script>

为了从 store 中提取属性时保持其响应性,你需要使用 storeToRefs()

访问state

const store = useStore()

store.count++

重置state

你可以通过调用 store 的 $reset() 方法将 state 重置为初始值。

const store = useStore()

store.$reset()

变更state

除了用 store.count++ 直接改变 store,你还可以调用 $patch方法。它允许你用一个 state 的补丁对象在同一时间更改多个属性:

store.$patch({
    
    
  count: store.count + 1,
  age: 120,
  name: 'DIO',
})

替换state

你不能完全替换掉 store 的 state,因为那样会破坏其响应性。但是,你可以 patch 它

// 这实际上并没有替换`$state`
store.$state = {
    
     count: 24 }
// 在它内部调用 `$patch()`:
store.$patch({
    
     count: 24 })

订阅state

你可以通过 store 的 $subscribe() 方法侦听 state 及其变化。

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 // 传递给 cartStore.$patch() 的补丁对象。

  // 每当状态发生变化时,将整个 state 持久化到本地存储。
  localStorage.setItem('cart', JSON.stringify(state))
})

getters

getter

Getter 完全等同于 store 的 state 的计算值。可以通过 defineStore() 中的 getters 属性来定义它们。推荐使用箭头函数,并且它将接收 state 作为第一个参数:

export const useStore = defineStore('main', {
    
    
  state: () => ({
    
    
    count: 0,
  }),
  getters: {
    
    
    doubleCount: (state) => state.count * 2,
  },
})
 <p>Double count is {
   
   { store.doubleCount }}</p>

访问其他的getter(使用普通函数)

export const useStore = defineStore('main', {
    
    
  state: () => ({
    
    
    count: 0,
  }),
  getters: {
    
    
    // 类型是自动推断出来的,因为我们没有使用 `this`
    doubleCount: (state) => state.count * 2,
    // 这里我们需要自己添加类型(在 JS 中使用 JSDoc)
    // 可以用 this 来引用 getter
    /**
     * 返回 count 的值乘以 2 加 1
     *
     * @returns {number}
     */
    doubleCountPlusOne() {
    
    
      // 自动补全 ✨
      return this.doubleCount + 1
    },
  },
})

向getter传递参数

Getter 只是幕后的计算属性,所以不可以向它们传递任何参数。不过,你可以从 getter 返回一个函数,该函数可以接受任意参数:

getUserById: (state) => {
    
    
      return (userId) => state.users.find((user) => user.id === userId)
}

访问其他 store 的 getter

想要使用另一个 store 的 getter 的话,那就直接在 getter 内使用就好:

import {
    
     useOtherStore } from './other-store'

export const useStore = defineStore('main', {
    
    
  state: () => ({
    
    
    // ...
  }),
  getters: {
    
    
    otherGetter(state) {
    
    
      const otherStore = useOtherStore()
      return state.localData + otherStore.data
    },
  },
})

actions

Action 相当于组件中的 method。它们可以通过 defineStore() 中的 actions 属性来定义,并且它们也是定义业务逻辑的完美选择。

export const useCounterStore = defineStore('main', {
    
    
  state: () => ({
    
    
    count: 0,
  }),
  actions: {
    
    
    increment() {
    
    
      this.count++
    },
    randomizeCounter() {
    
    
      this.count = Math.round(100 * Math.random())
    },
  },
})

类似 getter,action 也可通过 this 访问整个 store 实例,并支持完整的类型标注(以及自动补全✨)。不同的是,action 可以是异步的,你可以在它们里面 await 调用任何 API,以及其他 action!下面是一个使用 Mande 的例子。请注意,你使用什么库并不重要,只要你得到的是一个Promise,你甚至可以 (在浏览器中) 使用原生 fetch 函数:

猜你喜欢

转载自blog.csdn.net/weixin_61485030/article/details/132702810