1. Pinia 的介绍

状态管理是现代 Web 应用开发中的一个重要概念。Vue 3 中的状态管理库 Pinia,是一个基于Vue 3 Composition API的状态管理库,它提供了一种简单灵活的方式来管理应用程序的状态,同时还具有高性能可扩展性Pinia在某种程度上来说,也可以被叫做Vuex5,因为它结合了Vuex 5核心团队讨论中的许多想法,所以 Pinia被作为新的推荐方案来代替Vuex

2. Pinia 的优点

  • Devtools 支持
    • 追踪actionsmutations的时间线
    • 在组件中展示它们所用到的Store
    • 让调试更容易的Time travel
  • 热更新
    • 不必重载页面即可修改Store
    • 开发时可保持当前的State
  • 直接通过actions修改state中的数据。废弃了mutation
  • 不再有可命名的模块。取消了vuex中的module,每个Pinia模块都是独立的
  • 插件。可通过插件扩展Pinia功能
  • 更好的TypeScript支持。提供了代码补全功能,避免了过多魔法字符串的注入。
  • 支持服务端渲染
  • 体积更小。压缩后只有2.1KB

3. Pinia 的安装和使用

3.1. 安装

安装 Pinia 很简单,只需要使用 npm 或者 yarn 安装即可:

npm install pinia

# 或

yarn add pinia

3.2. 使用

3.1.1. 创建一个 Pinia Store

创建一个 Pinia Store 非常简单,下面是一个简单的示例:
Tips: 关于 Pinia Store 的命名,官方推荐的做法是 use+名称+Store

import { defineStore } from 'pinia'
// 你可以对 `defineStore()` 的返回值进行任意命名,但最好使用 store 的名字,同时以 `use` 开头且以 `Store` 结尾。(比如 `useUserStore`,`useCartStore`,`useProductStore`)
// 第一个参数是你的应用中 Store 的唯一 ID。
export const useCounterStore = defineStore({
  id: "counter",
  state: () => ({
    count: 0,
  }),
  actions: {
    increment() {
      this.count++;
    },
    decrement() {
      this.count--;
    },
  },
  getters: {
    doubleCount: ({ count }) => count * 2,
  },
});

在上面的代码中,我们首先使用 defineStore 函数创建了一个名为 useCounterStore 的 Pinia Store,然后在 state 函数中定义了一个 count 属性,最后在 actions 对象中定义了 incrementdecrement 两个方法来修改 count 属性。

当然了,我们用一个函数来定义 Store 也是同样可行的:

import { ref, computed } from "vue";
// 你可以对 `defineStore()` 的返回值进行任意命名,但最好使用 store 的名字,同时以 `use` 开头且以 `Store` 结尾。(比如 `useUserStore`,`useCartStore`,`useProductStore`)
// 第一个参数是你的应用中 Store 的唯一 ID。
export const useCounterStore = defineStore('counter', () => {
  const count = ref(0)
  const doubleCount = computed(() => count.value * 2);
  function increment() {
    count.value++
  }
  function decrement() {
    count.value--
  }

  return { count, doubleCount, increment, decrement }
})

3.2.2. 在组件中使用 Pinia Store

要在组件中使用 Pinia Store,我们需要将 Store 导入进来。

<script setup lang="ts">
import { useCounterStore } from "@/stores/counter";

const counterStore = useCounterStore()
// 注意此处不能直接采用结构赋值的方法:如 const { count, doubleCount } = useCounterStore()
// 这样会让数据失去响应性
</script>

想结构赋值的话,需要导入 storeToRefs 函数,将解构出来的参数变成响应式:

<script setup lang="ts">
import { storeToRefs } from 'pinia'
import { useCounterStore } from "@/stores/counter";

const counterStore = useCounterStore()
// 将解构出来的参数变成响应式
const { count, doubleCount } = storeToRefs(counterStore)
// 作为 action 的 increment 和 decrement 可以直接解构
const { increment, decrement } = counterStore 
</script>

3.2.3. 在模板中使用 Pinia Store

要在模板中使用 Pinia Store,我们在模板中直接使用就行了。

<template>
  <div>
    <p>Count: {{ counterStore.count }}</p>
    <p>doubleCount: {{ counterStore.doubleCount }}</p>
    <button @click="counterStore.increment()">Increment</button>
    <button @click="counterStore.decrement()">Decrement</button>
  </div>
</template>

4. Pinia 的状态管理和数据流

  • Pinia中,状态管理和数据流的概念非常重要。状态管理是指将应用程序的状态保存在一个中心化的地方,并通过一些方法来修改和查询状态。数据流是指数据在应用程序中的流动方式,包括数据的来源传输处理存储等方面。

  • Pinia中,我们可以使用Store来管理应用程序的状态,并使用ActionsGetters来修改和查询状态。Store 是一个包含状态、Actions 和 Getters 的对象,它可以被多个组件共享。当一个组件需要修改或查询状态时,它可以通过Store来访问状态,并调用相应的ActionsGetters来修改或查询状态。

  • Pinia中,数据的流动方式非常简单和直观。当一个组件调用Store中的Actions来修改状态时,数据会从组件流向 Store,然后从Store再流向其他组件。当一个组件调用Store中的Getters来查询状态时,数据会从Store流向组件。这种数据流的方式非常清晰和可控,使得我们可以更好地管理和维护应用程序的状态

5. Pinia 的模块化和命名空间

在 Pinia 中,我们可以使用模块化和命名空间来组织 Store,以便更好地管理和维护应用程序的状态。模块化和命名空间可以帮助我们将应用程序的状态分成多个逻辑模块,并将其组合成完整的应用程序状态。这种模块化和命名空间的方式非常清晰和可控,使得我们可以更好地管理和维护应用程序的状态。

5.1. 模块化

在 Pinia 中,我们可以使用 defineStore 函数来定义一个 Store。defineStore 函数可以接受一个参数对象,其中包含了 Store 的状态、Actions 和 Getters 等信息。我们可以将多个 defineStore 函数组合成一个完整的 Store,以便更好地管理和维护应用程序的状态。

import { defineStore } from 'pinia'

const counterStore = defineStore({
  id: 'counter',
  state: () => ({
    count: 0
  }),
  actions: {
    increment() {
      this.count++
    },
    decrement() {
      this.count--
    }
  },
  getters: {
    doubleCount: (state) => state.count * 2,
  },
})

const userStore = defineStore({
  id: 'user',
  state: () => ({
    name: '',
    email: ''
  }),
  actions: {
    setName(name) {
      this.name = name
    },
    setEmail(email) {
      this.email = email
    }
  }
})

export default {
  counterStore,
  userStore
}

在上面的代码中,我们首先使用 defineStore 函数定义了一个名为 counterStore 的 Store,其中包含了计数器状态和增加和减少计数器值的 Actions。然后,我们又使用 defineStore 函数定义了一个名为 userStore 的 Store,其中包含了用户信息状态和修改用户名和电子邮件的 Actions。最后,我们将 counterStoreuserStore 导出为一个对象,以便在其他组件中使用。

5.2. 命名空间

在 Pinia 中,我们可以使用命名空间来组织 Store。命名空间可以将多个 Store 分组,并将其组合成完整的应用程序状态。命名空间可以帮助我们更好地管理和维护应用程序的状态,避免了状态冲突和重复定义的问题。

import { createPinia } from 'pinia'
import { counterStore } from './counter'
import { userStore } from './user'

const pinia = createPinia()

pinia.useStore('counter', counterStore)
pinia.useStore('user', userStore)

export default pinia

在上面的代码中,我们首先使用 createPinia 函数创建了一个 Pinia 实例,然后使用 useStore 函数将 counterStoreuserStore 添加到了 Pinia 实例中,并分别使用了 counteruser 命名空间。这意味着,在其他组件中,我们可以通过 this.$pinia.store.counterthis.$pinia.store.user 来访问计数器 Store 和用户信息 Store。

6. Pinia 的插件机制和异步操作

6.1. 插件机制

在 Pinia 中,我们可以使用插件来扩展其功能。插件可以是一个简单的对象,也可以是一个包含多个函数的对象。我们可以使用 use 函数来添加插件。

import { createPinia } from 'pinia'

const pinia = createPinia()
const myPlugin = {
	// ...
}
pinia.use(myPlugin)

在上面的代码中,我们首先使用 createPinia 函数创建了一个 Pinia 实例,然后使用 use 函数将 myPlugin 添加到了 Pinia 实例中。

6.2. 异步操作

在 Pinia 中,我们可以使用异步操作来处理一些需要等待的数据。异步操作可以是一个 Promise,也可以是一个异步函数。我们可以使用 await 关键字来等待异步操作的结果。

import { defineStore } from 'pinia'

export const useUserStore = defineStore({
  id: 'user',
  state: () => ({
    name: '',
    email: ''
  }),
  actions: {
    async fetchUser() {
      const response = await fetch('/api/user')
      const data = await response.json()
      this.name = data.name
      this.email = data.email
    }
  }
})

在上面的代码中,我们首先使用 defineStore 函数定义了一个名为 useUserStore 的 Store,其中包含了用户信息状态和异步获取用户信息的 fetchUser 方法。在 fetchUser 方法中,我们首先使用 fetch 函数获取用户信息的数据,然后使用 await 关键字等待 fetch 函数的结果,并将其解析为 JSON 格式。最后,我们将获取的数据赋值给 Store 的状态。

Logo

前往低代码交流专区

更多推荐