Pinia状态管理

121 阅读3分钟

1. 概述

  • Pinia本质上依然是一个状态管理的库,用于跨组件、页面进行状态共享(这点和Vuex、Redux一样);
  • 与 Vuex 相比,Pinia 提供了一个更简单的 API,具有更少的仪式,提供了 Composition-API 风格的 API;
  • 最重要的是,在与 TypeScript 一起使用时具有可靠的类型推断支持

2. 和Vuex相比,Pinia的优势

  • 比如mutations不再存在:他们经常被认为是非常冗长;他们最初带来了 devtools 集成,但这不再是问题;
  • 更友好的TypeScript支持,Vuex之前对TS的支持很不友好;
  • 不再有modules的嵌套结构:你可以灵活使用每一个store,它们是通过扁平化的方式来相互使用的;
  • 也不再有命名空间的概念,不需要记住它们的复杂关系。

1.png

3. Pinia的使用

  • 安装
yarn add pinia
# 或者使用 npm
npm install pinia
  • 创建一个pinia并且将其传递给应用程序
import { createPinia } from 'pinia'

const pinia = createPinia()

export default pinia
  • 使用
import pinia from './stores'

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

4. 认识Store

  • 一个 Store (如 Pinia)是一个实体,它持有绑定到组件树状态业务逻辑,也就是保存了全局的状态;始终存在,且每个人都可以读取和写入的组件;可以在应用程序中定义任意数量的Store来管理状态。
  • 三个核心概念 state、getters、actions;等同于组件的data、computed、methods;一旦 store 被实例化,就可以直接在 store 上访问 state、getters 和 actions 中定义的任何属性。

(1)定义一个Store

  • Store 使用 defineStore() 定义;
  • 且它需要一个唯一名称,作为第一个参数传递:这个 name,也称为 id,是必要的,Pinia 使用它来将 store 连接到 devtools
  • 返回的函数统一使用useX作为命名方案,这是约定的规范。
import { defineStore } from 'pinia'

const useCounter = defineStore("counter", {
  ...  
})

export default useCounter

(2)使用定义的Store

  • Store在它被使用之前是不会创建的,可以通过调用use函数来使用Store。
<template>
  <div class="home">
    <h2>count: {{ counterStore.count }}</h2>
  </div>
</template>

<script setup>
  import useCounter from '@/stores/counter';

  const counterStore = useCounter()
</script>
  • 注意Store获取到后不能被解构,那么会失去响应式。为了从 Store 中提取属性同时保持其响应式,要使用storeToRefs()
  import { toRefs } from 'vue'
  import { storeToRefs } from 'pinia'
  
  const { count } = toRefs(counterStore)
  const { count } = storeToRefs(counterStore)

4.1 State

(1)认识和定义State

  • state 是 store 的核心部分,因为store是用来帮助我们管理状态的。在Pinia中,状态被定义为返回初始状态的函数
  state: () => ({
    count: 99,
    friends: [
      { id: 1, name: "a" },
      { id: 2, name: "b" },
    ]
  }),

(2)操作State

  • 读取和写入 state:默认情况下,可以通过 store 实例访问状态来直接读取和写入状态
  function incrementCount() {
    counterStore.count++
  }
  • 重置 State:可以通过调用 store 上的$reset()方法将状态重置到其初始值。
  function resetState() {
    userStore.$reset()
  }
  • 改变State:可以调用$patch方法;使用部分“state”对象同时应用多个更改。
    // 1.一个个修改状态
    userStore.name = "kobe"
    userStore.age = 20

    // 2.一次性修改多个状态
    userStore.$patch({
      name: "abab",
      age: 23
    })
  • 替换State:可以通过将其 $state 属性设置为新对象来替换Store 的整个状态。
   userStore.$state = {
      name: "cdcd",
      age: 24
    }

4.2 Getters

  • Getters相当于Store的计算属性:用 defineStore() 中的 getters 属性定义。getters中可以定义接受一个state作为参数的函数
  import useUser from './user'
  
  getters: {
    // 1.基本使用
    doubleCount(state) {
      return state.count * 2
    },
    // 2.一个getter引入另外一个getter
    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
          }
        }
      }
    },
    // 4.getters中用到别的store中的数据
    showMessage(state) {
      // 1.获取user信息
      const userStore = useUser()

      // 2.获取自己的信息

      // 3.拼接信息
      return `name:${userStore.name}-count:${state.count}`
    }
  },

4.3 Actions

  • Actions 相当于组件中的 methods。可以使用 defineStore() 中的 actions 属性定义,并且它们非常适合定义业务逻辑。和getters一样,在action中可以通过this访问整个store实例的所有操作;
  actions: {
    increment() {
      this.count++
    },
    incrementNum(num) {
      this.count += num
    }
  }
  • 并且Actions中是支持异步操作的,可以编写异步函数,在函数中使用await。
  actions: {
    async fetchHomeMultidata() {
      const res = await fetch("https://pinia.web3doc.top/introduction.html")
      const data = await res.json()
      return data
  }
<script setup>
  import useHome from '@/stores/home';

  const homeStore = useHome()
  homeStore.fetchHomeMultidata().then(res => {
    console.log("fetchHomeMultidata的action已经完成了:", res)
  })

</script>