乐趣区

关于前端:全新的-Vue3-状态管理工具Pinia

Vue3 公布曾经有一段时间了,它采纳了新的响应式零碎,而且构建了一套全新的 Composition API。Vue 的周边生态都在加紧适配这套新的零碎,官网的状态治理库 Vuex 也在适配中,为此官网提出了一个 Vuex 5 的全新提案。

  • 反对两种语法创立 Store:Options ApiComposition Api
  • 删除 mutations,只反对 stategettersactions
  • 模块化的设计,能很好反对代码宰割;
  • 没有嵌套的模块,只有 Store 的概念;
  • 残缺的 TypeScript 反对;

在这个提案下方,有个评论很有意思。简略翻译一下:

好巧不巧,Vuex5 的提案,与 Pinia 实现的性能不能说毫无关系,只能说截然不同,明天的文章就来给大家介绍一下这个菠萝。

装置

在现有我的项目中,用过如下命令进行 Pinia 模块的装置。

# yarn
yarn add pinia@next
# npm
npm i pinia@next

装置实现后,须要在 Vue3 我的项目的入口文件中,进行导入装置。

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

// 实例化 Vue
const app = createApp(App)
// 装置 Pinia
app.use(createPinia())
// 挂载在实在 DOM
app.mount('#app')

上手

要应用 Pinia 的话,只须要定义一个 store,而后在用到该数据的中央进行导入。

定义 Store

import {defineStore} from "pinia"

// 对外部裸露一个 use 办法,该办法会导出咱们定义的 state
const useCounterStore = defineStore({
  // 每个 store 的 id 必须惟一
  id: 'counter',
  // state 示意数据源
  state: () => ({count: 0}),
  // getters 相似于 computed,可对 state 的值进行二次计算
  getters: {double () {
        // getter 中的 this 指向👉 state
        return this.count * 2
      },
      // 如果应用箭头函数会导致 this 指向有问题
      // 能够在函数的第一个参数中拿到 state
    double: (state) => {return state.count * 2}
  },
  // actions 用来批改 state
  actions: {increment() {
      // action 中的 this 指向👉 state
      this.count++
    },
  }
})

export default useCounterStore

除了应用上述相似 vuex 的形式来构建 state,还能够应用 function 的模式来创立 store,有点相似于 Vue3 中的 setup()

import {ref, computed} from "vue"
import {defineStore} from "pinia"

// 对外部裸露一个 use 办法,该办法会导出咱们定义的 state
const useCounterStore = defineStore('counter', function () {const count = ref(0)
  const double = computed(() => count.value * 2)
  function increment() {count.value++}
  return {count, double, increment}
})

export default useCounterStore

应用 Store

后面也介绍过,Pinia 提供了两种形式来应用 store,Options ApiComposition Api 中都完满反对。

Options Api

Options Api 中,可间接应用官网提供的 mapActionsmapState 办法,导出 store 中的 state、getter、action,其用法与 Vuex 基本一致,很容易上手。

import {mapActions, mapState} from 'pinia'
import {useCounterStore} from '../model/counter'

export default {
  name: 'HelloWorld',
  computed: {...mapState(useCounterStore, ['count', 'double'])
  },
  methods: {...mapActions(useCounterStore, ['increment'])
  }
}

Composition Api

Composition Api 中,不论是 state 还是 getter 都须要通过 computed 办法来监听变动,这和 Options Api 中,须要放到 computed 对象中的情理一样。另外,Options Api 中拿到的 state 值是能够间接进行批改操作的,当然还是倡议写一个 action 来操作 state 值,不便前期保护。

// Composition Api
import {computed} from 'vue'
import {useCounterStore} from '../stores/counter'
export default {
  name: 'HelloWorld',
  setup() {const counter = useCounterStore()
    return {
      // state 和 getter 都须要在应用 computed,这和 Options Api 一样
      count: computed(() => counter.count),
      double: computed(() => counter.double),
      increment: () => { counter.count++}, // 能够间接批改 state 的值
      increment: counter.increment, // 能够援用 store 中定义的 action
    }
  }
}

类型提醒

在 Vuex 中,TypeScript 的类型提醒做得不是很好,在进行类型推导时,只能找到它的 state。特地是写代码的过程中,代码提醒就很不智能。

而 pinia,就能推导出定义的所有 state、getter、action,这样在写代码的时候,就会不便很多。

次要是 pinia 通过 TypeScript 进行了非常敌对的类型定义,感兴趣的能够看看 pinia 的类型定义文件(pinia.d.ts):

代码宰割

因为应用了模块化设计,所有的 store 都可能独自引入,而不是像 vuex 一样,通过 modules 的形式,将所有的 module 挂载到一个 store 上。

假如,咱们以后通过 Vuex 创立了一个 Store,这个 Store 下有两个 module,别离是用户模块(User)和商品模块(Goods)。即便以后首页只应用到了用户信息,然而整个 Store 都会被打包到首页的 js chunk 中。

如果咱们应用 pinia,咱们会应用 defineStore 定义两个 齐全是拆散状态的 store,两个页面在引入时,也互不影响。最初打包的时候,首页的 js chunk 和商品页的 js chunk 会别离打包对应的 store。


Pinia 的介绍到这里就告一段落了,如果当初有新我的项目要应用 Vue3 进行开发,举荐无脑应用 Pinia,更加简洁,而且大小仅 1KB。

退出移动版