介绍

跟 Vuex 一样是数据状态管理系统,但是这个更轻量,整个包的大小是 1kb 。

  • Vue2 和 Vue3 都支持
  • 相比 Vuex 有更好更完美的 **TypeScript** 支持
  • 模块化设计,你引入的每一个 store 在打包时都可以自动拆分他们
  • 没有模块嵌套,只有 store 的概念, store 之间可以自由使用,更好的代码分割。

Pinia vs Vuex

版本问题:

  • Vuex 当前最新版本是 4.x
    • Vuex 4 用于 Vue3
    • Vuex 3 用于 Vue2
  • Pinia 当前最新版本是 2.x
    • 既支持 Vue2 也支持 Vue3

Pinia api 与 Vuex ≤ 4 有很大不同,即:

  • 没有 **mutations**
  • 不再有模块的嵌套结构。
  • 更好的 typescript 支持。无需创建自定义的复杂包装器来支持 TypeScript ,所有内容都是类型化的,并且 API 的设计方式尽可能地利用 TS 类型推断。
  • 不再需要注入、导入函数、调用它们,享受自动补全。
  • 无需动态添加 stores,默认情况下它们都是动态的。
  • 没有命名空间模块。

    基本使用

    安装

    1. yarn add pinia
    2. // or
    3. npm install pinia

    如果你使用的是 vue2,你还需要安装组合式api : @vue/composition-api

注入

  1. import { createApp } from 'vue'
  2. import { createPinia } from 'pinia'
  3. const pinia = createPinia()
  4. createApp(App).use(pinia)

store

定义 store:

  1. import { defineStore } from 'pinia'
  2. /**
  3. * defineStore 第一个参数:storeId,必须唯一;
  4. * 第二个参数:配置对象
  5. * state、getters、actions属性
  6. */
  7. export const useStore = defineStore('main', {
  8. // other option
  9. })

使用 store:

  1. import { storeToRefs } from 'pinia'
  2. import { useStore } from '@/stores/counter'
  3. export default {
  4. setup() {
  5. const store = useStore()
  6. const { name, doubleCount } = storeToRefs(store)
  7. cosnt { increment } = store
  8. return {
  9. name,
  10. doubleCount,
  11. increment
  12. }
  13. }
  14. }

state

类似于组件的 data,用来存储全局状态。

  1. 必须是函数:为了在服务器渲染的时候避免交叉请求导致的数据状态污染
  2. 必须是箭头函数:为了更好的 TS 类型推导
  1. import { defineStore } from 'pinia'
  2. const useStore = defineStore('storeId', {
  3. state: () => {
  4. return {
  5. counter: 0,
  6. foo: 'hh',
  7. arr: [1, 2, 3]
  8. }
  9. }
  10. })

修改 state 的 4 种方式

我们可以 直接对 state 中的值进行更改

  1. const store = useStore()
  2. stote.counter++

也可以使用 $patch 来更改 state 中的多个属性值

  1. store.$patch({
  2. counter: store.counter + 1,
  3. name: 'hello'
  4. })

还可以给 $patch 传递函数,这种方式更适用于操作一些数组,对象等复杂一点的属性。

  1. store.$patch((state) => {
  2. state.arr.push(4)
  3. state.counter++
  4. })

通过 actions的方式

  1. store.changeState()

getters

类似于组件的 computed ,用来封装计算属性,有缓存功能,同一个 getters 就算被调用多次,只要值不变,依旧只执行一次。函数接收一个可选参数:state

  1. import { defineStore } from 'pinia'
  2. const useStore = defineStore('storeId', {
  3. state: () => {
  4. return {
  5. counter: 0,
  6. foo: 'hh',
  7. arr: [1, 2, 3]
  8. }
  9. },
  10. getters: {
  11. doubleCount: (state) => state.counter * 2,
  12. doubleCountPlusOne() {
  13. return this.doubleCount + 1
  14. },
  15. count10 (state) {
  16. return state.counter + 10
  17. }
  18. }
  19. })
  1. const store = useStore()
  2. store.doubleCount

actions

类似于组件的 methods ,封装业务逻辑,修改 state。同步异步都支持

tips:不能使用箭头函数定义 action ,因为箭头函数绑定外部 this

  1. import { defineStore } from 'pinia'
  2. const useStore = defineStore('storeId', {
  3. state: () => {
  4. return {
  5. counter: 0,
  6. foo: 'hh',
  7. arr: [1, 2, 3]
  8. }
  9. },
  10. actions: {
  11. changeState () {
  12. this.counter++
  13. this.foo = 'hello'
  14. this.arr.push(4)
  15. },
  16. async setUser() {
  17. const user = await Login()
  18. this.foo = user.foo
  19. }
  20. })

storeToRefs

如果直接解构 store 数据,会导致失去响应式,所以要用到 storeToRefs 。

  1. <script lang="ts" setup>
  2. import { storeToRefs } from 'pinia'
  3. import useCountStore from './store/counter'
  4. const counterStore = useCountStore()
  5. // 直接解构的话会造成数据失去响应式
  6. // 解决:要用到 storeToRefs
  7. const { count, double } = storeToRefs(counterStore)
  8. </script>

参考链接