前端工程化之配置Pinia

500 阅读3分钟

介绍

Pinia是Vue的一个全新状态管理(Store)库,可以理解为下一个版本的Vuex;也就是Vuex5.0;并且Pinia已经被纳入官方账户下,也就是github/vue.js下,并且Pinia的作者也是Vue的核心维护人员。注意:Pinia只支持Vue;

Pinia 最初是在2019年11月左右使用Composition API重新设计Vue Store。从那时起,最初的原则仍然相同,但Pinia同时适用于Vue 2和Vue 3,并且不要求您使用Composition API;当时的PR设计介绍了他基本的希望支持的功能:

  • 对Vue2和Vue3中Options API、Composition API的支持;
  • 没有mutations,只有state, getters, actions;
  • 不需要modules模块化拆分;
  • 对TypeScrip友好的支持;
  • 自动化代码拆分;
  • 支持Vue DevTools
  • 支持服务端渲染,支持插件扩展功能
  • 模块热更新:无需重新加载页面即可更改容器,热更新时候保持现有的状态

关于这个名字Pinia(发音为/piːnjʌ/,就像英语中的“peenya”)是最接近piña(西班牙语中的 “菠萝pineapple”)的一个有效的包名。事实上,菠萝是一群单独的花朵结合在一起,形成了多个果实的一种水果。与Stores类似,每个store都是独立生成的,但他们最终都是连接在一起的。菠萝也是一种原产于南美洲的美味热带水果。

Pinia与Vuex对比

Pinia从使用的角度和之前的Vuex几乎是一样的,但是比Vuex更简单了,Pinia的体积更小(性能更好);

一、核心概念

VuexPinia
StateState
GettersGetters
MutationsActions
Actions

二、版本问题

Vuex:当前最新版本为4.xPinia:当前版本为2.x
1.Vuex4.x用于Vue31.同时支持Vue2和Vue3
2.Vuex3.x用于Vue22.可以认为是Vuex5;并且被官方接管;

三、不同点

  • 没有mutations
  • 没有模块的嵌套结构,但是可以使用类似于hooks引入,在store之间交叉组合使用;
  • 更好的typecript支持
  • 随时受用使用store注册
  • 没有命名空间模块,扁平架构,可以认为所有的stores都是命名空间

注意:建议新项目使用Pinia;老项目可迁移;

Pinia使用

一、安装使用

1.引入

yarn add pinia
# or with npm
npm install pinia

2.使用

// main.ts
import { createPinia } from 'pinia'
app.use(createPinia())

// store/useUserStore.ts
import { defineStore } from 'pinia'
export const useUserStore = defineStore('storeId', {
  state: () => {
    return {
      count: 0,
    }
  },
  getters:{},
  actions:{}
})

// 组件中使用
import { useUserStore } from './store/useUserStore'
const store = useUserStore();
// const { count } = storeToRefs(store)

二、使用注意 Vue3中

import { defineStore } from 'pinia'

// 参数1:store的Id,必须是唯一的,将来Pinia会所有的store把挂在到根下
// 参数2:对象
// 返回值是一个函数,调用得到当前的store实例
export const useUserStore = defineStore('storeId', {
  /**
  *类似于Vue中的data,用来存储状态
  * 1.必需是函数:这是为了在服务端渲染避免交叉渲染请求导致的数据状态污染
  * 2.箭头函数,为了更好的TS类型推导
  */
  state: () => {
    return {
      storeId: 1234,
      userName: '张三',
      arr: [1,2,3],
      money: 1000
    }
  },
  
  /**
  * 类似于组件中的computed, 用来封装计算属性,有缓存功能
  */
  getters:{
    // 函数接受一个可选的state
    // moneyDouble (state) {
    //     console.log('moneyDouble')
    //     return state.money * 2
    // }
    
    // 如果在getters中使用了this,必须手动的指定返回值类型
    moneyDouble (): number{
        console.log('moneyDouble')
        return this.money * 2
    }
  },
  
  /**
  *	类似于组件中的methods,封装业务逻辑,修改state
  */
  actions:{
    changeState(val: string){ // 不能使用箭头函数,this
      this.userName = val + this.userName
      // this.$patch({})
      // this.$pathc(state=>{})
      
      // $reset() 将当前的store初始化
    }
  },
  
  // 插件:开启数据缓存
  persist: {
    enabled: true,
    strategies: [
      {
        storage: localStorage,
        paths: ['name', 'age']
      }
    ]
  }
})

使用方式和Hooks很类似,store之前的调用和在组件内部的调用是一样的;

  // 问题1:这样数据不是响应式的
  // const {storeId, userName} = store
  // 解决:storeRefs, 原因主要是由于Pinia把state做了reactive处理,用refs做响应式代理
  const {storeId, userName, moneyDouble} = storeToRefs(store)
  console.log(userName.value)

  // 问题2:修改数据的方式
  const changeName = ()=>{
    // 方式一:数据的修改--最简单
    store.userName = '李四'

    // 方式二:如果需要修改多个数据,建议使用$patch批量更新,内部做了优化
    store.$patch({
      userName: '李四',
      storeId: 5678
    })

    // 方式三:$patch传入一个函数,更好的批量更新
    store.$patch(state=>{
      state.userName =  '李四'
      state.storeId = 5678
      state.arr.push(5)
    })

    // 方式四:如果业务逻辑较为复杂使用action
    store.changeState('你好')
  }

其他API:

  • $subscribe():订阅State

1.和Vuex中的subscribe一样,类似于watch;与watch()相比,使用$subscribe()的优势在于,订阅只会在patches之后触发一次;

2.默认情况下,状态订阅被绑定到添加它们的组件上(如果store在组件的setup()中)。这意味着,当组件被卸载时,它们将被自动删除。如果你想在组件卸载后保留它们,传递{ detached: true } 作为第二个参数来从当前组件中分离状态订阅:

someStore.$subscribe(callback,{detached:true})

  • $onAction():订阅action

1.观察actions及其结果。传递给它的回调函数在action本身之前执行。在处理promises之后,允许您在action resolves之后执行函数;链接

2.支持第二个参数: someStore.$onAction(callback,true)

  • $dispose(): 注销store

三、插件使用

方式:pinia.use(Plugin)

Pinia持久化存储插件 文档
npm i pinia-plugin-persist --save

使用

import piniaPluginPersist from 'pinia-plugin-persist'

const store = createPinia()
store.use(piniaPluginPersist)