Pinia
介绍
vue专属的状态管理器,实现跨组件或页面共享状态
安装
yarn add pinia
npm install pinia
创建实例
vue3创建
import {createApp} from 'App'
import {createPinia} from 'Pinia'
import App from './App.vue'
coust pinia = createPinia()
coust app = createApp(App)
app.use(pinia)
app.mount('#app')
vue2创建
import {createPinia, PiniaVuePlugin} from 'Pinia'
VUe.use(PiniaVuePlugin)
coust pinia = createPinia()
new Vue({
el: '#app',
pinia,
})
Store
保存状态和业务逻辑的实体,它并不是和组件树进行绑定,它承载这全局的状态,相当于一个永远存在的组件,全局的组件都可以对他实现读取与写入
它有三个概念state、getter、action
对应于组件的data(数据)、compured(计算属性)、methods(方法)
定义store
store是通过defineStore()定义的
要求: 名称唯一性
常用写法: 返回的函数命名为use...
import {defineStore} from 'Pinia'
export const useAlertsStore = define('alerts', {
// 其他配置
})
defineStore()第二参数接受Option对象和Setup函数
Option Store:
export coust useCounterStore = defineStore('counter',{
state: ()=>({count: 0}),
getter: {
double: (state)=> state.count * 2
},
actions: {
increment() {
this.count++
},
},
})
Setup Store:
ref() 等同于 state
computed() 等同于 getters
function() 等同于 actions
export coust useCounterStore = defineStore('counter',() => {
const count = ref(0)
function increment() {
count.value++
}
return {count increment}
})
使用store
当通过<script setup></script>调用useStore()之前,store实例不会被创建
<script setup>
import { useCounterStore } from '@/stores/cpunter'
const store = useCounterStore()
</script>
当实例化后可直接访问store的state、getters、actions中定义的任何属性
例如:
const doubleValue = computed(() => store.doubleCount)
但不可以通过解构的方式将store进行解构:store是一个用reactive包装的对象
错误示例:
const {name, doubleCount} = store
为store提取属性保存响应,可使用storeToReds(),当只使用状态不调用任何action时
<script setup>
import { storeToRefs } from 'pinia'
const stor = useCounterStore()
const { name, doubleCount } = storeToRefs(store)
// 你可以直接从 store 中解构 action,因为它们也被绑定到 store 上
const { increment } = store
</script>
state
使用state
state是store的核心,state被定义为一个初始化状态的函数,使得Pinia可同时支持服务端和客户端
如果使用vue2,在state中创建的数据与vue实例中的data遵循同样的规则,当你想添加新属性时需要调用Vue.set()
import { defineStore } from 'pinia'
const useStoreIdStore = defineStore('storeId', {
state: ()=> {
return {
count: 0,
name: 'EEEEE',
isAdmin: false,
items: [],
}
}
})
TypeScript兼容
const userStoreIdStore = defineStore('storeId', {
state: () => {
return {
userList: [] as UserInfo[],
user: null as UserInfo | null,
}
}
})
interface UserInfo {
name: string
age: number
}
也可以通过接口直接定义state,并添加state的返回类型
interface State() {
userList: UserInfo
user: UserInfo | null
}
const userStoreIdStore = defineStore('storeId', {
state: (): State => {
return {
userList: [],
user: null,
}
}
})
interface UserInfo {
name: string
age: number
}
访问state
const store = userStoreIdStore()
store.count++
重置state
const store = userStoreIdStore()
store.$reset()
选项式API
通过mapState()辅助函数将state属性映射为计算属性
例如:
import { mapState } from 'pinia'
import { userCounterStore } from '../stores/counter'
export default {
computed: {
// 与store.count 中读取的数据相同
...mapState(useCounterStore, ['count'])
// 将其注册为this.myOwnName
...mapState(useCounterStor, {
myOwnName: 'count',
double: store => stor.count*2
// 可以传递函数
magicValue(store) {
return: store.someGetter + this.count + this.double
}
})
}
}
修改state:可以通过mapWritableState()
import { mapWritableStore } from 'pinia'
import { useCounterStore } from '../stores/counter'
export default {
computed: {
// 与store.count 中读取的数据相同
...mapWritableState(useCounterStore, ['count'])
// 将其注册为this.myOwnName
...mapWritableState(useCounterStor, {
myOwnName: 'count',
// 此处不可以传递函数
})
}
}
变更state
直接改变
例如:state.count++
调用$patch
允许用一个state补丁对象同时更改多个属性
state.$patch({
count: state.count + 1,
age: 120,
name: 'DIO',
})
$patch 方法也接受一个函数来组合这种难以用补丁对象实现的变更
state.$patch((state) => {
state.items.push({name: 'shoes', quantity: 1})
state.hasChanged = true
})
替换state
store的state不能被完全的替换,会影响响应性
store.$state = { count: 24 } // 此种方法实际上并没有去替换state
可以通过patch实现变更
store.$patch({
count: 24
})
也可以通过变更pinia实例的state来设置整个应用的初始state
pinia.state.value = {}
监听state
$subscribe()方法可监听state变化
与watch()区别: $subscribe()在patch后只会触发一次
carStore.$subscribe((mutation, state) => {
// import { MutationType } from 'pinia'
mutation.type // 'direct' | 'patch object' | 'patch function'
// 和 cartStore.$id 一样
mutation.storeId // 'cart'
// 只有 mutation.type === 'patch object'的情况下才可用
mutation.payload // 传递给 cartStore.$patch() 的补丁对象。
// 每当状态发生变化时,将整个 state 持久化到本地存储。
localStorage.setItem('cart', JSON.stringify(state))
})
默认情况下会绑定到添加他们的组件上,当组件卸载后,他们将自动的删除
如果想组件卸载后依旧保留可以将{detached: true}作为第二参数
<script setup>
const someStore = useSomeStore()
someStore.$subscribe(callback, { detached: true })
</script>
在pinia实例上监听整个state
watch(
pinia.state,
(state) => {
localStorage.setItem('cart', JSON.stringify(state))
}
)
Getters
定义Getters
Getters完全等同于store的state的计算值
可以在defineStore()中getters属性来定义
export const userStore = defineStore('main', {
state: () => ({
count: 0,
}),
getters: {
doubleCount: (state) => state.count * 2,
},
})
getter使用其他的getter:必须定义返回类型,通过this访问整个store实例
export const userStore = defineStore('main', {
state: () => ({
count: 0,
}),
getters: {
doubleCount(state) {
return state.count * 2
},
// 返回类型必须明确设置
doublePluOne() : number {
return this.doubleCount + 1
}
}
})
使用getters
<script setup>
import { userStore } from './counterStore'
const store = userStore()
</script>
<template>
<p>{{ store.doubleCount }}</p>
</template>
向getter传递参数
getter相当于计算属性,不可以向他们取传递参数,可以通过getter返回一个函数,通过函数接收参数
export const useUserListStore = defindeStore('userList', {
getters: {
getUserId: (store) => {
return (userId) => state.user.find((user) => user.id = userId)
}
}
})
使用
<script setup>
import { storeToRefs } from 'pinia'
import { useUserListStore } from './store'
const userList = useUserListStore()
const { getUserId } = storeToRefs(userList)
</script>
<template>
{{ getUserId(2) }}
</template>
访问其他store的getter
import { useOthreStore } from './other-store'