为什么说不学Pinia你就out了。
Pinia是下一代Vue状态管理库,在Vue-cli中已经替换了原来的Vuex,且同时支持Vue2.0和Vue3.0两个大版本。Pinia简化了状态管理,抛弃了Vuex中的mutation
,只有 state, getter
和 action
,且完美支持TypeScript
及Vue3.0的hooks
,可以很好的进行代码分割。
一、安装Pinia
初始化项目: npm init vite@latest
安装Pinia: npm i pinia
import { createApp } from 'vue'
import App from './App.vue'
// 导入构造函数
import { createPinia } from 'pinia'
// 创建Vue应用实例app
const app = createApp(App)
// 应用以插件形式挂载Pinia实例
app.use(createPinia())
app.mount('#app')
二、创建全局状态store
// stores/counter.ts
// 引入仓库定义函数
import { defineStore } from 'pinia'
// 传入2个参数,定义仓库并导出
// 第一个参数唯一不可重复,字符串类型,作为仓库ID以区分仓库
// 第二个参数,以对象形式配置仓库的state,getters,actions
export const useCounterStore = defineStore('counter', {
// 存储全局状态
state: () => {
return { name: 'hello pinia', count: 0 }
},
// 用来封装计算属性,有缓存功能,类似于computed
getters: {
getName(state) {
return state.name + '...'
}
},
// 处理业务逻辑,对state中的数据进行修改
actions: {
increment() {
this.count++
},
subtract() {
this.count--
}
}
})
三、基本示例
一旦仓库被实例化,就可以直接通过实例对象访问仓库上的state
、getters
和actions
中定义的任何属性。
<template>
<h1 style="color: blue">{{ store.getName }}</h1>
<h2>数值变化:{{ store.count }}</h2>
<button type="button" @click="store.increment">点击 + 1</button>
<button type="button" @click="store.subtract">点击 - 1</button>
</template>
<script setup lang="ts">
// 在需要使用状态的组件内需要先导入仓库:
import { useCounterStore } from '../stores/counter'
// 实例化仓库
const store = useCounterStore()
</script>
四、数据解构
Pinia中的store是一个用reactive包装的对象,不能直接通过ES6规范进行解构,因为这样做会使状态不具有响应性。
为了保持状态的响应行,应通过storeToRefs
API 对仓库实例结构以便获取状态。
<template>
<h1 style="color: blue">name属性示例:{{ name }}</h1>
<h1 style="color: green">getter属性示例:{{ store.getName }}</h1>
<h1>数值变化:{{ count }}</h1>
<button type="button" @click="store.increment">点击 + 1</button>
<button type="button" @click="store.subtract">点击 - 1</button>
</template>
<script setup lang="ts">
// 在需要使用状态的组件内需要先导入状态仓库:
import { storeToRefs } from 'pinia'
import { useCounterStore } from '../stores/counter'
// 实例化仓库函数
const store = useCounterStore()
const { name, count } = storeToRefs(store)
</script>
五、数据修改
Pinia中数据修改可以一次修改一个状态,也可以一次修改多个状态。
修改单个状态比较简单,不像Vuex每次需要调用Vuex的api,Pinia中,修改单个状态,可直接通过仓库函数的实例直接调用。
如以下示例中修改name值
// stores/name.ts
import { defineStore } from 'pinia'
export const useCounterStore = defineStore('counter', {
state: () => {
return { name: 'hello pinia', count: 0 }
},
getters: {
getName(state) {
return state.name + '...'
}
},
actions: {
setName(val: string) {
this.name = val
},
increment() {
this.count++
}
}
})
<template>
<h1 style="color: blue">name属性示例:{{ store.name }}</h1>
<h1 style="color: green">getter属性示例:{{ store.getName }}</h1>
<button type="button" @click="store.setName('修改了name')">点击修改name</button>
</template>
<script setup lang="ts">
import { useCounterStore } from '../stores/counter'
const store = useCounterStore()
</script>
修改多条状态,Pinia中一次修改多条状态,需要通过官方提供的$patch
,$patch
方法可以接受的参数类型可以是一个函数也可以是一个对象对象。
<template>
<h1 style="color: blue">count:{{ store.count }}</h1>
<h1 style="color: green">name:{{ store.name }}</h1>
<button type="button" @click="changeState">点击修改store中的状态</button>
<button type="button" @click="changeState2">点击修改store中的状态</button>
</template>
<script setup lang="ts">
// 在需要使用状态的组件内需要先导入状态仓库:
import { useCounterStore } from '../stores/counter'
// 实例化仓库函数
const store = useCounterStore()
const changeState = () => {
store.$patch({
count: 2,
name: '通过$patch的对象形式修改了名称'
})
}
const changeState2 = () => {
store.$patch(state => {
state.count = 4
state.name = '通过$patch的函数形式修改了名称'
})
}
</script>
6、多仓库之间的调用
在 Pinia 中,可以在一个 store
中 import
另外一个 store
,然后通过调用引入 store 方法的形式,获取引入 store
的状态。
定义config
// stores/config.ts
import { defineStore } from 'pinia'
export const useConfigStore = defineStore('config', {
state: () => {
return {
primaryColor: '#5468ff'
}
},
getters: {},
actions: {}
})
定义name
// stores/name.ts
import { defineStore } from 'pinia'
import { useConfigStore } from './config'
export const useCounterStore = defineStore('counter', {
state: () => {
return { name: 'hello pinia', count: 0 }
},
getters: {
getName(state) {
return state.name + '...'
},
// 调用外部的store
getConfig() {
const config = useConfigStore()
return config.primaryColor
}
},
actions: {
setName(val: string) {
this.name = val
},
increment() {
this.count++
}
}
})
应用仓库数据
<template>
<h1 style="color: blue">count:{{ store.count }}</h1>
<h1 style="color: green">name:{{ store.name }}</h1>
<!-- 获取另外一个config中的配置 -->
<h1 style="color: green">name:{{ store.getConfig }}</h1>
</template>
<script setup lang="ts">
// 在需要使用状态的组件内需要先导入状态仓库:
import { useCounterStore } from '../stores/name'
// 实例化仓库函数
const store = useCounterStore()
</script>
Pinia个人感触最深的是对于TypeScript
的兼容,无论是在模板语法或者是逻辑处理中,都可以完美的提示仓库上的state
、getters
和actions
中定义的任何属性。