Pinia

782 阅读2分钟

pinia.vuejs.org/zh/

Pinia基本介绍

什么是Pinia

Pinia 是 Vue 的专属状态管理库,它允许你跨组件或页面共享状态。

  1. 状态管理库Store是一个保存状态业务逻辑 的实体,每个组件都可以读取写入它。
  2. 它有三个概念:state、getter、action
    1. state为各个组件需要共享的状态,相当于组件中的data
    2. getter为状态代理(在获取状态时对状态进行变更),相当于组件中的computed
    3. action为对状态的一系列操作,相当于组件中的methods

Pinia与组件hooks的区别

pinia就是将多个组件需要共享的状态抽取出来,实现跨组件和页面共享状态。它与hooks的区别在于,hooks是对功能模块的封装和拆分,让其有更高的复用性,目标是解耦和复用功能模块,而pinia的目标是共享和维护状态

搭建 pinia 环境

  1. 下载pinia到项目 npm install pinia
  2. 注册使用pinia
import { createApp } from "vue";
// 导入根组件
import App from './App.vue'
// 导入pinia
import { createPinia } from "pinia";
// 创建pinia
const pinia = createPinia()
// 创建根组件
const app = createApp(App)
// 注册pinia
app.use(pinia)
app.mount('#app')

此时开发者工具中已经有了pinia选项表示pinia已经安装到项目中

Pinia的基本操作

存储状态

存储sum,num变量状态:src/store/count.ts

// 导入store
import { defineStore } from "pinia";

export const useCountStore = defineStore('count', {
  // 动作
  actions: {
    // 加
    increment(value: number) {
      // 进行逻辑判断,若sum值小于10再进行加
      if (this.sum < 10) this.sum += value;
    },
    // 减
    decrement(value: number) {
      if (this.sum > 1) {
        this.sum -= value
      }
    }
  },
  // 状态
  state() {
    return {
      sum: 6,
      num: 0
    }
  },
  // 计算
  getters: {}
})

获取状态

<script setup lang="ts" name="Count">
  // 导入sum状态管理构造器
  import { useCountStore } from '@/store/count'
  // 创建状态管理器
  const countStore = useCountStore()
  // 第一种获取方式,直接获取方式
  let sum = countStore.sum
  // 第二种获取方式,通过$state获取
  let sum = countStore.$state.sum
</script>

修改状态

第一种修改方式,直接修改

countStore.sum = 666

第二种修改方式:批量修改

countStore.$patch({
  sum:999,
  num:1
})

第三种修改方式:借助action修改(action中可以编写一些业务逻辑)

组件中调用action即可

<script setup lang="ts" name="Count">
  // 导入sum状态管理构造器
  import { useCountStore } from '@/store/count'
  // 创建状态管理器
  const countStore = useCountStore()
  // 调用对应action
  countStore.incrementOdd(n.value)
</script>

pinia的进阶操作

storeToRefs

当需要获取的状态是响应式的时候可以借助storeToRefsstore中的数据转为ref对象,方便在模板中使用。

<template>
  <div class="count">
    <h2>当前求和为:{{sum}}</h2>
  </div>
</template>

<script setup lang="ts" name="Count">
  import { useCountStore } from '@/store/count'
  /* 引入storeToRefs */
  import { storeToRefs } from 'pinia'

  /* 得到countStore */
  const countStore = useCountStore()
  /* 使用storeToRefs转换countStore,随后解构 */
  const {sum} = storeToRefs(countStore)
</script>

提示:pinia提供的storeToRefs只会将状态数据转换为响应式,而VuetoRefs会转换store全部数据为响应式。所以不要使用VuetoRefs来将状态中的数据进行响应式转换,代价太大,如下图

let sotre = toRefs(countStore)

getters

state中的数据,需要经过处理后再使用时,可以使用getters配置。

state() {
  return {
    sum: 6,
    num: 0
  }
},
// 计算
getters: {
  mutipleSum(state) {
    return state.sum * 10
  },
  decoratorNum(state): string {
    // this就是state
    return "点击次数为:" + this.num
  }
}

获取状态

// 导入sum状态管理构造器
import { useCountStore } from '@/store/count'
// 导入pinia的状态转换器
import { storeToRefs } from 'pinia'
// 创建状态管理器
const countStore = useCountStore()
// 将状态转换为响应式数据
let { sum, mutipleSum, decoratorNum } = storeToRefs(countStore)

$subscribe

state保存着talkList这一状态

state() {
  return {
    talkList: JSON.parse(localStorage.getItem("talkList") as string) || []
  }
},

通过 store 的 $subscribe() 方法侦听 state 及其变化,当store中的状态发生变化的时候会触发回调函数。

talkStore.$subscribe((mutate,state)=>{
  localStorage.setItem('talk',JSON.stringify(talkList.value))
})

提示:$subscribe可以解决刷新丢失状态的问题

store组合式写法

import {defineStore} from 'pinia'
import axios from 'axios'
import {nanoid} from 'nanoid'
import {reactive} from 'vue'

export const useTalkStore = defineStore('talk',()=>{
  // talkList就是state
  const talkList = reactive(
    JSON.parse(localStorage.getItem('talkList') as string) || []
  )
  // getATalk函数相当于action
  async function getATalk(){
    // 发请求,下面这行的写法是:连续解构赋值+重命名
    let {data:{content:title}} = await axios.get('https://api.uomg.com/api/rand.qinghua?format=json')
    // 把请求回来的字符串,包装成一个对象
    let obj = {id:nanoid(),title}
    // 放到数组中
    talkList.unshift(obj)
  }
  // 一定要交出去
  return {talkList,getATalk}
})