状态管理
在开发中,我们会的应用程序需要处理各种各样的数据,这些数据需要保存在我们应用程序中的某一个位置,对于这些数据的管理我们就称之为是 状态管理
✅ vue2 / Options Api 建议使用
vuex
✅ vue3 / Composition Api 建议使用
pinia
Vuex
创建Store
每一个Vuex应用的核心就是 store(仓库)
vuex
和 单纯的全局对象区别:
- Vuex的状态存储是响应式的:
store
中的状态发生变化,那么读取store
数据相应的组件也会被更新 - 不能直接改变
store
的状态 : 改变store中的状态的唯一途径就显示提交(commit) mutation
安装 vuex install vuex
注意:Vue2 安装 Vuex3,Vue3 安装 Vuex4,版本需对应。
创建文件 src/store/index.js
const store = createStore({ |
main.js
配置 store
import { createApp } from 'vue' |
在组件中访问使用 state 里的状态 $store.state.xxx
<tempate> |
vuex 五个核心概念
State
Vuex 管理的状态对象
在 /store/index.js
定义相关管理的状态数据
const store = createStore({ |
在组件 vue 里 使用:$store.state.xxx
<template> |
mapState
如果我们有很多个状态都需要获取话,可以使用mapState的辅助函数
- mapState的方式一:对象类型
- mapState的方式二:数组类型
- 也可以使用展开运算符和来原有的computed混合在一起
<template> |
在setup
中使用mapState
- 通过useStore拿到store后去获取某个状态
默认情况下,Vuex并没有提供
setup
非常方便的使用 mapState 的方式,这里我们进行了一个函数的封装
import { useStore, mapState } from 'vuex' |
使用
import useState from "../hooks/useState" |
gettters
官方定义:Vuex 允许我们在 store 中定义
getter
(可以认为是 store 的计算属性)
Getter 接受 state 作为其第一个参数
// ...省略初始化配置 |
在组件中访问使用 getters 里的状态 $store.getters.xxx
<template> |
使用 第二个参数getters
可以获取其他的 getters
getters: { |
getters 是可以返回一个函数的, 调用这个函数可以传入参数
getFriendById(state) { |
组件使用
<h2>id-111的朋友信息: {{ $store.getters.getFriendById(111) }}</h2> |
mapGetters
mapGetters
辅助函数仅仅是将 store 中的 getter 映射到局部计算属性
import { mapGetters } from 'vuex' |
如果你想将一个 getter 属性另取一个名字,使用对象形式:
...mapGetters({ |
Mutation
更改 Vuex 的 store 中的状态的唯一方法是提交
mutation
// ...省略初始化配置 |
组件使用
<button @click="changeName">修改name</button> |
对象风格的提交方式
提交 mutation 的另一种方式是直接使用包含 type
属性的对象:
store.commit({ |
❗重要的原则: 不要在mutation方法中执行异步操作
Mutation常量类型
定义常量:mutation-type.js
export const CHANGE_INFO = "changeInfo" |
定义mutation
[CHANGE_INFO](state, newInfo) { |
提交mutation
$store.commit({ |
mapMutations
借助于辅助函数,帮助我们快速映射到对应的方法中
...mapMutations(["changeName", "incrementLevel", CHANGE_INFO]) |
与上面mapState
用法大致相同
Actions
Action类似于mutation,不同在于:
- Action提交的是mutation,而不是直接变更状态
- Action可以包含任意异步操作
参数context
context
是一个和 store 实例均有相同方法和属性的 context对象- 所以我们可以从其中获取到
commit
方法来提交一个mutation
,或者通过context.state
和context.getters
来获取state
和getters
定义
actions: { |
使用
counterBtnClick(){ |
mapActions
action也有对应的辅助函数与上面大致相同
import { mapActions } from 'vuex' |
actions的异步操作
我们可以通过让 action 返回 Promise,在Promise 的 then 中来处理完成后的操作
actions: { |
const store = useStore() |
module
让代码更好维护,让多种数据分类更加明确,每一类数据及其相关操作对应一个
store
每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块
对于模块内部的 mutation 和 getter,接收的第一个参数是模块的局部状态对象
const moduleA = { |
同样,对于模块内部的 action,局部状态通过 context.state
暴露出来,根节点状态则为 context.rootState
const moduleA = { |
对于模块内部的 getter,根节点状态会作为第三个参数暴露出来:
const moduleA = { |
module的命名空间
- 默认情况下,模块内部的action和mutation仍然是注册在全局的命名空间中的
- 这样使得多个模块能够对同一个 action 或 mutation 作出响应
- Getter 同样也默认注册在全局命名空间;
- 希望模块具有更高的封装度和复用性,可以添加
namespaced: true
的方式使其成为带命名空间的模块:- 当模块被注册后,它的所有
getter、action
及mutation
都会自动根据模块注册的路径调整命名
- 当模块被注册后,它的所有
在 action 中修改 root 中的 state
changeNameActtion({commit,dispattch,sttate,rootState,getters,rootGetters}){ |
pinia
与 Vuex 相比,Pinia 提供了一个更简单的 API,具有更少的规范,提供了 Composition-API 风格的 API,最重要的是,在与 TypeScript 一起使用时具有可靠的类型推断支持 官网链接
安装
npm install pinia |
创建一个pinia并且将其传递给应用程序
新建 /store/index.js
import {createPinia} from 'pinia' |
在 main.js
注册
import pinia from './store/index.js' |
Store
- 一个 Store (如 Pinia)是一个实体,它会持有为绑定到你组件树的状态和业务逻辑,也就是保存了全局的状态
- 它有点像始终存在,并且每个人都可以读取和写入的组件
- 你可以在你的应用程序中定义任意数量的 Store 来管理你的状态
Store有三个核心概念:
- state、getters、actions
- 等同于组件的 data、computed、methods
- 一旦 store 被实例化,你就可以直接在 store 上访问 state、getters 和 actions 中定义的任何属性
定义一个 Store
Store 是使用
defineStore()
定义的,需要一个唯一名称,作为第一个参数传递
import { defineStore } from 'pinia' |
这个 name,也称为 id,是必要的,Pinia 使用它来将 store 连接到 devtools。
返回的函数统一使用
useXXX
作为命名方案,这是约定的规范
使用 Store
store 在它被使用之前是不会创建的,我们可以通过调用 use 函数来使用 Store
<template> |
如果对获取到的 Store 解构,那么会失去响应式,可使用
storeToRefs()
重新保持其响应性
State
state 是 store 的核心部分,因为store是用来帮助我们管理状态的。
定义:
import { defineStore } from 'pinia' |
操作 State
const store = useStore()
- 读取和写入:
store.count++
,通过 store 实例访问状态来直接读取和写入状态 - 重置 State:
store.$reset()
, 重置 到其初始值 - 改变 State:
store.$patch({ count: 100 })
,允许您使用部分 “state” 对象同时应用多个更改 - 替换 State:
store.$state = { count: 1 }
,设置为新对象来替换 Store 的整个状态
Getters
Getters相当于Store的计算属性,可以通过
defineStore()
中的getters
属性来定义它们
getters
中可以定义接受一个state
作为参数的函数
export const useStore = defineStore('main', { |
访问 Getters
访问当前 store 的 Getters
const store = useStore() |
Getters 中访问自己的其他 Getters
通过this来访问到当前store实例的所有其他属性
doublePlusOne: function(state) { |
访问其他 store 的Getters
message: function(state){ |
Getters也可以返回一个函数,接受参数
const useCounter = defineStore("counter", { |
使用
const counter = useCounter() |
Actions
Actions 相当于组件中的 methods,使用 defineStore() 中的 actions 属性定义
getters一样,在 action 中可以通过 this 访问整个 store 实例的所有操作
定义
actions: { |
使用
const counter = useCounter() |
Actions 中是支持异步操作的,并且我们可以编写异步函数,在函数中使用 await