下一代Vuex(Pinia)不学你就out了
为什么说不学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应用实例appconst app = createApp(App)// 应用以插件形式挂载Pinia实例app.use(createPinia())app.mount('#app')
二、创建全局状态store
// stores/counter.ts// 引入仓库定义函数import { defineStore } from 'pinia'// 传入2个参数,定义仓库并导出// 第一个参数唯一不可重复,字符串类型,作为仓库ID以区分仓库// 第二个参数,以对象形式配置仓库的state,getters,actionsexport 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.tsimport { 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.tsimport { defineStore } from 'pinia'export const useConfigStore = defineStore('config', { state: () => { return { primaryColor: '#5468ff' } }, getters: {}, actions: {}})
定义name
// stores/name.tsimport { 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
中定义的任何属性。
7、往期内容已全部收录在专栏中:
Flutter专栏_WEB前端李志杰的博客-CSDN博客
Vue专栏_WEB前端李志杰的博客-CSDN博客