介绍
Pinia
是一个全新的Vue状态管理库,是Vuex
的替代品。
Vue2
和Vue3
都能支持- 抛弃传统的
Mutation
,只有state
、getter
和action
,简化状态管理库 - 不需要嵌套模块,符合
Vue3
的Composition API
,让代码扁平化;因为在Pinia
中每个store
都是独立的,互相不影响 TypeScript
支持- 代码简洁,很好的代码自动分割
Pinia
中的action
支持同步和异步Pinia
支持插件来扩展自身功能- 支持服务端渲染
基本使用
初始化项目:npm create vite@latest
安装Pinia
:npm i pinia
挂载Pinia
// src/main.js
import {
createPinia } from 'pinia'
const pinia = createPinia()
app.use(pinia)
Store
创建store
一个Store
是一个实体,它持有未绑定到您的组件树的状态和业务逻辑。它托管全局状态。Store
是使用defineStore()
定义的,并且它需要一个唯一名称,作为第一个参数传递:
name
:也称为id
,必传项,该store
的唯一id
options
:一个对象,store
的配置项,比如配置store
内的数据,修改数据的方法等
import {
defineStore } from 'pinia'
export const useMainStore = defineStore('main', {
state: () => {
return {
msg: 'Hello World!',
count: 1
}
},
getters: {
},
actions: {
}
})
使用store
<script setup>
import { useMainStore } from '../store/index'
const store = useMainStore()
</script>
<template>
<h2>{
{ store.msg }}</h2>
</template>
解构store
store
是一个用reactive
包裹的对象,这意味着不需要在getter
之后写.value
,但是,就像setup
中的props
一样,不能对其进行解构。为了从store
中提取属性同时保持其响应式,需要使用storeToRefs()
。它将为任何响应式属性创建refs
。
<script setup>
import { useMainStore } from '../store/index'
import { storeToRefs } from 'pinia'
const store = useMainStore()
const { count } = storeToRefs(store)
</script>
<template>
<h2>{
{ store.msg }}</h2>
<h3>Count is: {
{ count }}</h3>
</template>
重置状态
可以通过调用store
上的$reset()
方法将状态重置到其初始值。
const store = useMainStore()
store.$reset()
Pinia
修改数据状态
简单数据类型
简单数据直接通过在方法中操作store.xxx
来修改
const store = useMainStore()
store.count++
多条数据修改
在进行多条数据修改的时候,推荐使用$patch
方法,它可以接受两个类型的参数,函数 和 对象
$patch
+ 对象$patch
+ 函数:通过函数方式去使用的时候,函数接受一个state
的参数,state
就是store
仓库中的state
<script setup>
import { useMainStore } from '../store/index'
const store = useMainStore()
// $patch + 对象
const onObjClick = () => {
store.$patch({
count: store.count + 2,
msg: '对象修改之后的内容'
})
}
// $patch + 函数
const onFunClick = () => {
store.$patch(state => {
state.count += 2
state.msg = '函数修改之后的内容'
})
}
</script>
<template>
<h2>store.count:{
{ store.count }}</h2>
<h2>store.msg:{
{ store.msg }}</h2>
<button @click="onObjClick">修改状态($patch + 对象)</button>
<button @click="onFunClick">修改状态($patch + 函数)</button>
</template>
替换state
可以通过将其$state
属性设置为新对象来替换store
的整个状态,这种场景比较少见。
store.$state = {
count: 0,
msg: '替换之后的内容'
}
Getters
Getter
完全等同于Store
状态的计算属性。接收state
作为第一个参数的箭头函数使用。getter
中的值有缓存特性,如果值没有改变,多次使用也只会调用一次。大多数情况下,getter
只会依赖state
,但是,他们也可能需要使用其他getter
,所以我们可以在定义常规函数是通过this
访问到整个store
的实例,但是需要定义返回类型(在TypeScript
中)。这是由于TypeScript
中的一个已知限制,并且不会影响使用箭头函数定义的getter
,也不会影响不使用this
的getter
。
export const useMainStore = defineStore('main', {
state: () => {
count: 0
},
getters: {
// 自动判断返回类型
doubleCount(state) {
console.log('getter被调用')
return `state.count的值:${
state.count * 2}`
},
// 返回类型必须明确设置
doublePlusOne(): number {
return this.count * 2 + 1
}
}
})
getter
传递参数
Getters
只是computed
的幕后场景,因此无法向它们传递任何参数。但是可以从getter
返回一个函数用于接收任何参数。
// src/store/index.js
export const useMainStore = defineStore('main', {
getters: {
getUserById: state => {
return userId => {
state.users.find(user => user.id === userId)
}
}
}
})
在组件中使用
<script setup>
import {useMainStore} from '../store/index'
cosnt store = userMainStore()
</script>
<template>
<h2>User 2: {
{ store.getUserById(1) }}</h2>
</template>
再执行此操作时,getter
不再缓存,它们只是调用函数。但是可以在getter
本身内部缓存一些结果,这并不常见,但应该性能会提高。
// src/store/index.js
export const useMainStore = defineStore('main', {
getters: {
getActiveUserById: state => {
const activeUsers = state.users.filter((user) => user.active)
return userId => activeUsers.find((user) => user.id === userId)
}
}
})
访问其他store
的getter
在Pinia
中,可以在一个store
中import
另外一个store
,然后通过调用引入store
方法的形式,获取引入store
的状态。
// src/store/other.js
export const useOtherStore = defineStore('other', {
state: () => {
return {
otherList: ['other1', 'other2', 'other3']
}
}
})
在原store
中引入useOtherStore
import {
defineStore} from 'pinia'
import {
useOtherStore} from './other'
export const useMainStore = defineStore('main', {
state: () => {
return {
count: 0,
msg: 'hello'
}
},
getters: {
getOtherStoreList() {
const otherStore = useOtherStore()
return otherStore.otherList
}
}
})
Actions
actions
相当于组件中methods
,他们可以使用defineStore()
中的actions
属性定义,且非常适合定义业务逻辑。
export const useMainStore = defineStore('main', {
state: () => {
return {
counter: 0,
userData: null
}
},
actions: {
// 同步操作
increment() {
this.counter++
},
randomizeCounter() {
this.counter = Math.round(100 * Math.random())
},
// 异步操作
async registerUser(login, password) {
try {
this.userData = await api.post({
login, password })
showTooltip(`Welcome back ${
this.userData.name}!`)
} catch (error) {
showTooltip(error)
// 让表单组件显示错误
return error
}
}
}
})
访问其他store
操作
import {
useAuthStore } from './auth-store'
export const useSettingsStore = defineStore('settings', {
state: () => ({
// ...
}),
actions: {
async fetchUserPreferences(preferences) {
const auth = useAuthStore()
if (auth.isAuthenticated) {
this.preferences = await fetchPreferences()
} else {
throw new Error('User must be authenticated')
}
}
}
})