Vue3.js store 状态管理库 pinia,Composition API 使用更友好

作者: tww844475003 分类: 前端开发 发布时间: 2023-09-01 21:12

Pinia 是 Vue 的存储库,它允许您跨组件/页面共享状态。同时支持 vue2 和 vue3。

安装

yarn add pinia

使用

创建一个 pinia 并将其传递给应用程序

// main.ts
import { createPinia } from 'pinia'

createApp(App).use(createPinia()).use(router).mount('#app')

State

定义一个 ‘Counter’ store

import { defineStore } from 'pinia'

export const useCounterStore = defineStore('Counter', {
  state: () => {
    return {
      count: 0
    }
  }
})

使用 stroe

<script lang="ts" setup>
import { useCounterStore } from '../store/counter' 

const counterStore = useCounterStore()
</script>

<template>
  <div class="pinia-box">
    {{ counterStore.count }}
  </div>
</template>

<style lang="less" scoped>
.pinia-box {
  padding: 20px;
}
</style>

与计算属性 computed

import { computed } from 'vue'
const doubleCounter = computed(() => counterStore.count * 2)

改变 store

const increment = (): void => {
  counterStore.count++
}
const decrement = (): void => {
  counterStore.count--
}

还可用使用 $patch 改变 store

const increment = (): void => {
  counterStore.$patch({
    count: counterStore.count + 2
  })
}

替换 store

const replaceStore = (): void => {
  counterStore.$state = {
    count: 100
  }
}

订阅 store

可以通过 store 的 $subscribe() 方法查看状态及其变化,类似于 Vuex 的 subscribe 方法

counterStore.$subscribe((mutation, state) => {
  console.log(mutation.type, state)
})

注意:

默认情况下,state subscriptions 绑定到添加它们的组件(如果 store 位于组件的 setup() 中)。 意思是,当组件被卸载时,它们将被自动删除。 如果要在卸载组件后保留它们,请将 { detached: true } 作为第二个参数传递给 detach 当前组件的 state subscription

counterStore.$subscribe(function() {
  // 此订阅将在组件卸载后保留
}, { detached: true })

Getters

Getter 完全等同于 Store 状态的 计算值。 它们可以用 defineStore() 中的 getters 属性定义。

getter 依赖状态

export const useCounterStore = defineStore('Counter', {
  state: () => {
    return {
      count: 0
    }
  },
  getters: {
    doubleCount: (state) => state.count * 2
  }
})

getter 依赖另外一个 getter

与计算属性一样,您可以组合多个 getter。 通过 this 访问任何其他 getter。

import { defineStore } from 'pinia'

export const useCounterStore = defineStore('Counter', {
  state: () => {
    return {
      count: 0 
    }
  },
  getters: {
    doubleCount: (state): number => state.count * 2,
    doubleCountPlusOne: (state): number => (state as any).doubleCount + 1
  }
})

getter 参数传入

请注意,在执行此操作时,getter 不再缓存,它们只是您调用的函数。

import { defineStore } from 'pinia'

export const useCounterStore = defineStore('Counter', {
  state: () => {
    return {
      count: 0 
    }
  },
  getters: {
    multipleCount: (state) => {
      return (coefficient: number) => state.count * coefficient
    }
  }
})

访问其它 store 中的 getter

import { defineStore } from 'pinia'
import { useUserStore } from './user'

export const useCounterStore = defineStore('Counter', {
  state: () => {
    return {
      count: 0 
    }
  },
  getters: {
    loginUserName: (state) => {
      return useUserStore().user.name
    }
  }
})

Actions

Actions 相当于组件中的 methods。 它们可以使用 defineStore() 中的 actions 属性定义,并且它们非常适合定义业务逻辑

import { defineStore } from 'pinia'

export const useCounterStore = defineStore('Counter', {
  state: () => {
    return {
      count: 0 
    }
  },
  actions: {
    increment() {
      this.count++
    },
    decrement() {
      this.count--
    }
  }
})

注意:这里的 actions 与 vuex 中的 actions 不等同,这里不仅仅是异步任务,同步任务也在这里。Pinia 没有 mutation 方法。

异步 actions

import { defineStore } from 'pinia'

export const useUserStore = defineStore('user', {
  state: () => ({
    user: {
      name: '游客'
    },
  }),
  getters: {
    isLoggedIn: (state) => !!state.user,
  },
  actions: {
    // 登录
    async login(userName, password) {
      const result = await api.post({ userName, password})
      this.user = result
    },
    // 登出
    async logout() {
      this.$reset() 
    },
  },
})

访问其它 store 操作,与 getter 一样。

Plugins

使用 pinia.use() 将插件添加到 pinia 实例中。 最简单的例子是通过返回一个对象为所有Store添加一个静态属性:

import { createApp } from 'vue'
import './style.css'
import App from './App.vue'
import router from './router'
import { createPinia } from 'pinia'

function AuthPiniaPlugin() {
  return {
    isAuth: true
  }
}

const pinia = createPinia()
pinia.use(AuthPiniaPlugin)

createApp(App).use(pinia).use(router).mount('#app')

添加外部属性,与 router 结合

import { markRaw } from 'vue'
import { router } from './router'

pinia.use(({ store }) => {
  store.router = markRaw(router)
})

在插件中调用 $subscribe

您也可以在插件中使用 store.$subscribe 和 store.$onAction :

pinia.use(({ store }) => {
  store.$subscribe(() => {
    // 在存储变化的时候执行
  })
  store.$onAction(() => {
    // 在 action 的时候执行
  })
})

Pinia 与 Vuex 区别

Vuex 和 Pinia 都是用于管理 Vue.js 应用程序状态的官方状态管理库。它们都提供了一种集中式存储来管理组件的状态,并且都可以在组件之间共享状态。

VuexPinia
相同点– 都是官方支持的状态管理库
– 都提供了一种集中式存储来管理组件的状态
– 都可以在组件之间共享状态
– 都是官方支持的状态管理库
– 都提供了一种集中式存储来管理组件的状态
– 都可以在组件之间共享状态
不同点– Vuex 是专门为 Vue.js 设计的,而 Pinia 是为现代化的 Vue.js 应用程序设计的
– Vuex 使用 ES6 类语法,而 Pinia 使用 ES6 函数语法
– Vuex 提供了更多的功能,例如模块、插件等,而 Pinia 则更注重简单性和易用性
– Vuex 的学习曲线较陡峭,需要掌握一些概念和模式,而 Pinia 则更加直观和易于上手
– Vuex 是专门为 Vue.js 设计的,而 Pinia 是为现代化的 Vue.js 应用程序设计的
– Vuex 使用 ES6 类语法,而 Pinia 使用 ES6 函数语法
– Vuex 提供了更多的功能,例如模块、插件等,而 Pinia 则更注重简单性和易用性
– Vuex 的学习曲线较陡峭,需要掌握一些概念和模式,而 Pinia 则更加直观和易于上手
前端开发那点事
微信公众号搜索“前端开发那点事”

如果觉得我的文章对您有用,请随意打赏。您的支持将鼓励我继续创作!

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注