如何用Pinia来处理Vue组件间数据共享

2,423 阅读2分钟

Pinia

Pinia是Vue官方出的存储库,可以在组件或页面间共享数据。Pinia是官方用来取代Vuex库的。相比于Vuex,Pinia更加简洁,而且支持组合式API。

安装

可以通过npm或pnpm进行安装,如下:

pnpm install pinia

然后需要创建一个pinia实例并注册成vue插件,如下:

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')

开始使用

下面是一个简单的例子:

// stores/counter.js
import { defineStore } from 'pinia'

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

这里defineStore的第一个参数是id,也就是name,所以也可以这样写:

export const useCounterStore = defineStore({
  id:'counter', 
  state: () => {
    ...
  },
  ...
})

使用的时候:

import { useCounterStore } from '@/stores/counter'

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

    counter.count++
    // or using an action instead
    counter.increment()
  },
}

组合式API

上面defineStore也可以使用组合式API,如下:

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

  return { count, increment }
})

在组合式API中,ref相当于statecomputed相当于gettersfunction相当于actions

响应性

Pinia会默认将store实例包装成reactive,这样保证了响应性。但是如果对store进行解构,为了保持响应性,需要使用storeToRefs(),如下:

<script setup>
import { storeToRefs } from 'pinia'

const store = useStore()
  
//const { name, doubleCount } = store             //这样会失去响应性
const { name, doubleCount } = storeToRefs(store)  //保持响应性
</script>    

State

上面知道我们可以直接访问和修改state。但是也有另外一种方法,官方为store对象添加几个函数是关于state的,如下:

$reset

将state重制回初始状态

$patch

修改state,主要作用是可以同时修改几个数据,如:

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

这个函数也可以接受一个function参数,用来处理更复杂的修改,比如为列表添加元素:

cartStore.$patch((state) => {
  state.items.push({ name: 'shoes', quantity: 1 })
  state.hasChanged = true
})

$state

替换state,上面$patch函数只是修改几个数据,而这个函数则完全替换整个state。

$subscribe

监听state的变化,如下:

cartStore.$subscribe((mutation, state) => {
  // import { MutationType } from 'pinia'
  mutation.type // 'direct' | 'patch object' | 'patch function'
  // same as cartStore.$id
  mutation.storeId // 'cart'
  // only available with mutation.type === 'patch object'
  mutation.payload // patch object passed to cartStore.$patch()

  // persist the whole state to the local storage whenever it changes
  localStorage.setItem('cart', JSON.stringify(state))
})

Getters

上面提到过,getters等同于computed()

注意:getters中不能定义与state中同名的元素,否则会报错。

Actions

上面提到过,actions等同于function

store对象有一个函数$onAction可以用来监听action,如下:

export default {
  setup() {
    const someStore = useSomeStore()
    someStore.$onAction(callback, true)
  },
}

组件外使用

在组件外使用要格外注意,比如我们在一个工具类js文件中去使用,如下:

//utils.js
import { useCounterStore } from '@/stores/counter'

const counter = useCounterStore()

这样会报错,应该这时候Pinia还没有创建和装载到APP上,所以const counter = useCounterStore()要放到合适的地方,时机必须是确定Pinia已经创建装载到应用后。