import { defineStore } from 'pinia'
// the first argument is a unique id of the store across your application
export const useAlertsStore = defineStore('storeID', option)
e.g. `useUserStore`, `useCartStore`, `useProductStore`
storeID: string -> unique id of the store
option: a Setup function or an Options object.
// stores/counter.js
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('counter', {
state: () => {
return { count: 0 }
},
// 也可以这样定义
// state: () => ({ count: 0 })
actions: {
increment() {
this.count++
},
},
})
export const useCounterStore = defineStore('counter', () => {
const count = ref(0)
function increment() {
count.value++
}
return { count, increment }
})
tips:
ref()s become state properties
computed()s become getters
function()s become actions
<script setup>
import { useCounterStore } from '@/stores/counter'
// access the `store` variable anywhere in the component ✨
const store = useCounterStore()
</script>
tips: 不要使用解构或者使用storeToRefs
interface State {
userList: UserInfo[]
user: UserInfo | null
}
export const useUserStore = defineStore('user', {
state: (): State => {
return {
userList: [],
user: null,
}
},
})
interface UserInfo {
name: string
age: number
}
store.$reset()
store.$patch((state) => {
state.items.push({ name: ‘shoes’, quantity: 1 })
state.hasChanged = true
})
export const useCounterStore = defineStore('counter', {
state: () => ({
count: 0,
}),
getters: {
doubleCount: (state) => state.count * 2,
},
})
export const useStore = defineStore('main', {
getters: {
getUserById: (state) => {
return (userId) => state.users.find((user) => user.id === userId)
},
},
})
// setup
export const useStore = defineStore('main', () => {
const state: UserInfo = []
const getUserById = computed(() => state.users.find((user) => user.id === userId))
return {state, getUserById}
})
export const useCounterStore = defineStore('counter', {
state: () => ({
count: 0,
}),
actions: {
// since we rely on `this`, we cannot use an arrow function
increment() {
this.count++
},
randomizeCounter() {
this.count = Math.round(100 * Math.random())
},
async getUserInfo() {
const res = await api.getInfo()
return res
}
},
})
// if used setup ways
export const useCounterStore = defineStore('counter', () => ({
const count = 100
const increment = () => count++ // increment
const randomizeCounter = () => Math.round(100 * Math.random())
const getUserInfo = async() => {
const res = await api.getInfo()
return res
}
return { count, increment, randomize }
})
Pinia 提供了插件机制,可以通过插件扩展和定制化存储。插件可以用于实现各种功能,如持久化存储、日志记录、网络请求等
import { createPinia } from 'pinia'
import { createPersist } from 'pinia-persist'
const pinia = createPinia()
const persist = createPersist({
// 配置选项
})
pinia.use(persist)
pinia-persist 的配置选项包括:
key:要在本地存储中使用的键名,默认为 ‘pinia-state’。
paths:要持久化的状态路径数组,默认为 [],表示持久化整个状态。
storage:要使用的存储引擎,默认为 localStorage。你可以使用其他存储引擎,如 sessionStorage 或自定义的存储引擎。
will always run after pinia is installed.
import { createRouter } from 'vue-router'
const router = createRouter({
// ...
})
// ❌ Depending on the order of imports this will fail
const store = useStore()
router.beforeEach((to, from, next) => {
// we wanted to use the store here
if (store.isLoggedIn) next()
else next('/login')
})
router.beforeEach((to) => {
// ✅ This will work because the router starts its navigation after
// the router is installed and pinia will be installed too
const store = useStore()
if (to.meta.requiresAuth && !store.isLoggedIn) return '/login'
})
在 Pinia 中,你可以使用 mapState 和 mapActions 辅助函数来简化在组件中使用存储的状态和操作。这些辅助函数可以帮助你将存储的状态和操作映射到组件的计算属性和方法中。
使用 mapState 辅助函数:
mapState 辅助函数用于将存储的状态映射到组件的计算属性中。它接收一个字符串数组或对象作为参数,并返回一个包含计算属性的对象。
import { mapState } from 'pinia'
export default {
setup() {
const { count } = mapState(['count'])
return {
count,
}
},
}
// 使用对象的方式:
import { mapState } from 'pinia'
export default {
setup() {
const { count } = mapState({
count: 'count',
})
return {
count,
}
},
}
在上面的示例中,我们使用 mapState 辅助函数将存储中的 count 状态映射到组件的计算属性中。通过这种方式,我们可以在组件中直接使用 count 计算属性来获取存储中的状态值。
mapActions 辅助函数用于将存储的操作映射到组件的方法中。它接收一个字符串数组或对象作为参数,并返回一个包含方法的对象。
使用字符串数组的方式:
import { mapActions } from 'pinia'
export default {
setup() {
const { increment } = mapActions(['increment'])
return {
increment,
}
},
}
// 使用对象的方式:
import { mapActions } from 'pinia'
export default {
setup() {
const { increment } = mapActions({
increment: 'increment',
})
return {
increment,
}
},
}
在上面的示例中,我们使用 mapActions 辅助函数将存储中的 increment 操作映射到组件的方法中。通过这种方式,我们可以在组件中直接调用 increment 方法来触发存储中的操作。
使用 mapState 和 mapActions 辅助函数可以使你在组件中更方便地使用存储的状态和操作,减少了手动引用和订阅的过程。这样可以使你的代码更简洁和易读。
import { useUserStore } from './user'
export const useCartStore = defineStore('cart', () => {
const user = useUserStore()
const list = ref([])
const summary = computed(() => {
return `Hi ${user.name}, you have ${list.value.length} items in your cart. It costs ${price.value}.`
})
function purchase() {
return apiPurchase(user.id, this.list)
}
return { summary, purchase }
})
Pinia 是一个基于 Vue 3 的状态管理库,它提供了一种简单、直观和强类型的方式来管理应用程序的状态。下面是对 Pinia 的总结:
强类型支持: Pinia 是为 TypeScript 设计的,提供了完整的类型支持。它使用了 Vue 3 的 Composition API,可以在开发过程中进行类型推断和类型检查,使代码更可靠和易于维护。
基于 Store 的架构: Pinia 的核心概念是 Store,每个 Store 对象都代表了一个独立的状态管理单元。通过定义 Store,你可以组织和管理应用程序的状态,并在组件中访问和修改这些状态。
使用简单: Pinia 的 API 设计简洁、直观,易于上手和使用。它采用了类似于 Vue 3 的 Composition API 的风格,使用 defineStore
函数来定义 Store,使用 useStore
函数在组件中访问 Store。
插件扩展: Pinia 提供了插件机制,可以通过插件来扩展和定制化存储。你可以使用插件来实现持久化存储、日志记录、网络请求等功能,或者开发自己的插件来满足特定需求。
优化性能: Pinia 在内部使用了 Vue 3 的响应式系统,具有高效的状态更新和依赖追踪机制。它使用了类似于 Vuex 的订阅-发布模式,只有在状态发生改变时,相关的组件才会重新渲染,从而提高了应用程序的性能。
总体而言,Pinia 是一个功能强大且易于使用的状态管理库,适用于 Vue 3 的项目。它提供了强类型支持、简单的 API、基于 Store 的架构和插件扩展机制,帮助开发者更好地组织和管理应用程序的状态,并提供了性能优化的解决方案。如果你正在开发一个 Vue 3 的应用程序,并需要一个可靠和灵活的状态管理库,Pinia 是一个值得考虑的选择。