您的位置:

深入吕昕开发的vuex插件:Pinia

一、简介

Pinia 是一个由 Vue.js 核心成员 Luy 带头开发的 Vuex 替代品,它基于 Vue 3 composition API 构建,提供了一种更加简洁优雅的状态管理方案。

相比于 Vuex,Pinia在以下几个方面提供了显著的改进:

  • 支持 TypeScript
  • 数据响应式更新更加优化
  • 使用 composition API 来进行状态管理编写
  • 提供了插件机制,易于扩展
  • 支持多个 store 实例创建

二、安装和基本使用

安装 Pinia:

npm install pinia

在 Vue 3 的应用中,使用 createApp() 方法来创建实例:

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

const app = createApp(App)
app.use(createPinia())

app.mount('#app')

上述代码中,我们使用 createPinia() 方法来创建一个名为 Pinia 的插件,同时将其安装到 Vue 3 实例上,然后通过 app.mount() 来挂载应用。

接下来,来看一下如何在组件内部使用 Pinia 插件。

首先,需要定义一个 store 实例。

import { defineStore } from 'pinia'

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

上面代码中,我们使用 defineStore() 方法来定义一个名为 useCounterStore 的 store 实例,其中包含 state、mutations 和 actions 等属性。

在使用 defineStore() 方法时,需要传入一个配置对象,其中包含以下属性:

  • id: String 类型,用来唯一标识此 store 实例。
  • state: Function 类型,用来返回此 store 实例的状态对象。
  • actions: Object 类型,包含多个用于更新状态的方法。
  • mutations: Object 类型,包含多个用于更新状态的方法。
  • getters: Object 类型,包含多个读取状态值的方法。
  • actionsContext: Object 类型,包含多个上下文相关的方法。
  • mutationsContext: Object 类型,包含多个上下文相关的方法。

接下来,通过 useStore() 方法来使用 store 实例:

import { useCounterStore } from './store'

export default {
  setup() {
    const store = useCounterStore()

    const handleIncrement = () => {
      store.increment()
    }

    return {
      handleIncrement,
      count: store.count
    }
  }
}

上面的代码中,我们使用 useCounterStore() 来获取 useCounterStore 这个 store 实例对象,并将其赋值给一个变量 store,接着通过调用 store 实例对象中的 increment 方法来更新 count 状态值的值。

三、插件机制

在需要对 Pinia 进行扩展或者自定义时,可以使用 Pinia 提供的 plugin 机制来实现,插件可以为 Store 实例添加更多的能力和特性,如:日志记录、数据持久化等。

下面是一个使用插件的示例:

import { createPinia } from 'pinia'
import { Storage } from '@ionic/storage'

const storage = new Storage()

const store = createPinia()

store.use((pinia) => {
  pinia.$onAction(({ type, payload }, state) => {
    console.log(`Action ${type} with payload`, payload, `updated with state`, state)
  })
  pinia.$onMutation(({ type, payload }) => {
    console.log(`Mutation ${type} with payload`, payload)
  })
  pinia.$subscribe((mutation, state) => {
    storage.set(mutation.type, state)
  })
  pinia.$restore(({ type }) => {
    return storage.get(type)
  })
})

上述代码中,我们使用 use() 方法来安装插件,然后在回调函数内部对 Store 实例添加了四个功能:

  • 使用 $onAction 方法来监听 actions 的修改,并在控制台中输出相关信息。
  • 使用 $onMutation 方法来监听 mutations 的修改,并在控制台中输出相关信息。
  • 使用 $subscribe 方法来监听 state 的修改,并将修改后的数据进行持久化。
  • 使用 $restore 方法来获取持久化的数据并还原到 store 实例中。

四、多个实例的创建

Pinia 提供多个 Store 实例的创建方式,可以根据不同的需要创建不同的实例。

下面是一个多个实例同时运行的示例:

// file: store.js

import { defineStore } from 'pinia'

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

export const useTodoStore = defineStore({
  id: 'todo',
  state: () => ({
    todos: []
  }),
  actions: {
    add(todo) {
      this.todos.push(todo)
    }
  }
})

上述代码中,我们分别定义了两个 store 实例 useCounterStore 和 useTodoStore。

// file: main.js

import { createApp } from 'vue'
import { createPinia } from 'pinia'

import App from './App.vue'
import { useCounterStore } from './store'

const app1 = createApp(App)
const app2 = createApp(App)

app1.use(createPinia())
app2.use(createPinia())

const store1 = useCounterStore()
const store2 = useCounterStore()

app1.config.globalProperties.$store = store1
app2.config.globalProperties.$store = store2

app1.mount('#app1')
app2.mount('#app2')

上述代码中,我们首先通过 createApp() 方法来创建两个不同的 Vue 3 实例 app1 和 app2,接着分别为两个实例都安装了 Pinia,并声明了两个不同的 useCounterStore 实例对象 store1 和 store2,最后将 store 实例存放到每个实例的全局属性中,最终通过 app1 和 app2 来分别将两个实例挂载到不同的元素上。

五、总结

通过上述的介绍,可以看出 Pinia 是一个功能强大的状态管理方案,它比 Vuex 更加简单、直观、灵活,是 Vue 3 开发中值得推荐的一款工具。

在使用 Pinia 时,需要注意以下几点:

  • 需要安装插件才能够实现更多的功能;
  • 支持 TypeScript,需要进行类型约束;
  • 使用 composition API 编写状态管理逻辑;
  • 支持多个 Store 实例的创建。