状态管理

@ Pinia
Vue3 采用 Pinia;Pinia 是 Vue 的专属状态管理库,使用大菠萝作为 logo
Vue2 采用 vuex
状态管理出现之前,使用共享组件完成对共享数据的使用;共享数据的修改通过共享组件发送自定义事件完成。这就意味着:任何一个使用它的组件都可以修改,不太容易维护;注意:共享数据和全局数据不是一回事
Overview
是一个保存全局状态 state 和业务逻辑的实体;可以在 整个应用 中访问的数据
利用仓库 store 集中式状态管理:抽取出组件间的共享状态,放在一个全局单例中来管理
不与组件树绑定,而承载着全局状态
仓库通常集中保存在项目的 stores 目录(应提前创建好),并按照功能创建 单独 的仓库文件
仓库在 onMounted 之前就已经准备好 - 兵马未动,粮草先行
更多信息,请访问 Pinia - setup-stores
Concepts
State - 驱动整个应用的数据源;是 store 的核心。应先定义能代表应用或反映应用状态的 state;相当于组件中的 data
Getter - 对状态的一种声明式映射;相当于组件中的 computed
Action - 根据用户的交互对数据源的操作;相当于组件中的 method
关系
Deployment
强烈建议在创建项目的时,选择状态管理;项目创建完毕后,可以直接使用
也可以单独安装,需要引入、配置等;不建议新手使用
在开发者视图中,使用慢速网络查看状态变化
1. Installation
npm i pinia --save
2. Import
在入口文件 main.js 引入并创建使用
完成后,在开发者工具中可以看到大菠萝
在 main.js 中引入并使用
import './assets/main.css'

import { createApp } from 'vue'
import App from './App.vue'
//1. 导入
import { createPinia } from 'pinia'
//2. 创建
const pinia = createPinia()
const app = createApp(App)
//3. 使用
app.use(pinia)
app.mount('#app')
Procedure

. 在默认示例的基础增加 msg

创建仓库文件 .js,使用语义化命名,如 counter.js
引入 defineStore 库及其它必要库
使用 defineStore 创建仓库实例,其中:

. 第一个参数 counter 是你的应用中 Store 的唯一 ID,Pinia 将用它来连接 store 和 devtools

. 第二个参数接收 option 对象或 setup 函数;setup 函数和组合式 API 类似,且功能更灵活

导出仓库示例,以 use 开头且以 Store 结尾命名,如 useCounterStore
import { defineStore } from 'pinia'
import { ref, computed } from 'vue'

export const useCounterStore  = defineStore('counter', ()=>{
  //state - ref()
  const count = ref(0)
  const msg = ref('hi,there.')
  
  //getters - computed()
  const doubleCount = computed( () => count.value * 2 )
  
  //action - function()
  const increment = () => count.value++

  return { count, msg, doubleCount, increment }
})
目标组件使用 Store

逻辑 - 引入仓库、创建仓库实例、使用仓库数据;创建仓库实例前无法使用

<script setup>
    import { useCounterStore } from '@/stores/counter';
    const store = useCounterStore();
    console.log('store', store);
</script>

结构 - 渲染仓库数据;这里采用内联事件

<template>
    <div>{{ store.count }}</div>
    <div>{{ store.msg }}</div>
    <div>{{ store.doubleCount }}</div>
    <div @click="store.increment">store handle</div>
</template>
Warning
直接 解构 使用 store 中的数据(方法)会丢失响应:当仓库状态变化时,count 不变,相当于是获取了仓库的一次性数据
let { count, increment } = counterStore;
<div>仓库数据 - {{ store.count }} - {{ count }}</div>
使用 storeToRefs 包保持响应式 - 不建议;命名冲突。。。可读性不好。。。运维困难。。。
import { storeToRefs } from 'pinia';
let { count, increment } = storeToRefs(counterStore);