提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
- 前言
- 一、什么是状态管理?
- 二、复杂的状态管理
- 1.随着代码越来越多,需要管理的状态越来越复杂,当`多个组件共享状态`时,单向数据流的简洁性很容易被破坏
- 2.我们是否可以通过组件数据的传递来完成呢?
- Vuex的状态管理
- 管理不断变化的state本身是非常困难的
- 因此,我们是否可以考虑将组件的内部状态抽离出来,以一个全局单例(对象)的方式来管理
- 安装
- 创建Store
- Vuex和单纯的全局对象有什么区别呢
- 单一状态树
- 组件获取状态
- 在展开运算符和原来的computed混合使用 mapState
- getters的基本使用
- 某些属性我们需要经过变化后再使用,此时,可以使用getters进行操作
- getters第二个参数
- getters可以接收第二个参数
- getters的返回函数
- getters中的函数本身,可以返回一个函数,在使用的地方相当于可以调用这个函数
- Mutation基本使用
- 更改Vuex的store中的状态的唯一方法是提交mutation
- 携带数据
- 使用参数 传递数据
- payload为对象类型时 .
- 提交方式
- Mutation常量类型
- 定义常量:mutation-type.js
- 定义 mutation
- mapMutations辅助函数
- 在setup中使用方式:
- mutation重要原则
- actions的基本使用
- `actions`的`分发`操作
- actions的辅助函数
- actions的异步操作
- module的基本使用
- module的局部状态
- module的命名空间
前言
提示:这里可以添加本文要记录的大概内容:
例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。
提示:以下是本篇文章正文内容,下面案例可供参考
一、什么是状态管理?
✌✌✌🧨🧨🧨
- 在开发中,应用程序需要处理各种各样的数据,保存在我们应用程序中的某一个位置,那么对于这些数据的管理就可以称之为
状态管理
- 简单数据是如何管理自己的状态呢
组件化的开发方式
,在组件中我们定义data或者在setup中返回使用的数据,可以称之为state
- 在模块
template
中使用的数据,渲染成 DOM,称之为View - 组件中会产生一些行为事件,处理这些行为事件时,会修改
state
称之为actions
二、复杂的状态管理
1.随着代码越来越多,需要管理的状态越来越复杂,当多个组件共享状态
时,单向数据流的简洁性很容易被破坏
- 多个视图依赖于同一状态
- 来自不同视图的行为需要变更同一状态
2.我们是否可以通过组件数据的传递来完成呢?
- 对于一些
简单的状态
,确实可以通过props的传递或者Provide的方式
来共享状态 - 但是对于
复杂的状态
管理来说,显然单纯通过传递和共享的方式是不足以解决问题的
Vuex的状态管理
管理不断变化的state本身是非常困难的
- 状态之间相互会存在依赖,一个状态的变化会引起另一个状态的变化,View页面也有可能会引起状态的变化
- 当应用程序复杂时,state在什么时候,因为什么原因而发生了变化,发生了怎么样的变化,会变得非常难以控制和追踪
因此,我们是否可以考虑将组件的内部状态抽离出来,以一个全局单例(对象)的方式来管理
- 在这种模式下,我们的组件树构成了一个巨大的 “视图View”
- 不管在树的哪个位置,
任何组件都能获取状态或者触发行为
- 通过定义和隔离状态管理中的各个概念,并通过
强制性的规则来维护视图和状态间的独立性
,我们的代码边会变得更加结构
化和易于维护、跟踪 - 这就是Vuex背后的基本思想
安装
-
npm install vuex
-
计数器案例(组件内定义的方式)
创建Store
- 每一个Vuex应用的核心就是
store
(仓库)
本质是一个容器,包含着应用中大部分的状态
入口文件main.js中
组件中使用 模板使用
script中使用store
Vuex和单纯的全局对象有什么区别呢
-
Vuex的状态存储是
响应式
全局对象不是响应式的
当Vue组件从store中读取状态的时候,若store中的状态发生变化,那么相应的组件也会被更新 -
但是,不能直接改变store中的状态
改变store中的状态的唯一途径就是提交 (commit)mutation
这样使得我们可以方便的跟踪每一个状态的变化,从而让我们能够通过一些工具帮助我们更好的管理应用的状态
单一状态树
- Vuex使用单一状态树
用一个对象
就包含了全部的应用层级的状态
采用的SSOT
是单一数据源 - 意味 每个应用将仅仅包含一个
store 实例
单状态树和模块化并不冲突, - 优势:
相比较保存到多个Store对象中,后期的维护会变得复杂
单一状态树可以最直接的方式找到某个状态的片段
利于后期维护和调试,
组件获取状态
- 在模块中获取时,表达式过长,使用计算属性也较为繁琐
- 所以,如果有很多个状态都需要获取的话,我们使用vuex提供的辅助函数,mapState 映射
展开运算符和原来的computed混合使用
参数:
方式一:对象类型
方式二:数组类型
在展开运算符和原来的computed混合使用 mapState
getters的基本使用
某些属性我们需要经过变化后再使用,此时,可以使用getters进行操作
store/index.js
getters第二个参数
getters可以接收第二个参数
getters的返回函数
getters中的函数本身,可以返回一个函数,在使用的地方相当于可以调用这个函数
Mutation基本使用
更改Vuex的store中的状态的唯一方法是提交mutation
携带数据
使用参数 传递数据
payload为对象类型时 .
提交方式
Mutation常量类型
定义常量:mutation-type.js
export const ADD_NUMBER = ‘ADD_NUMBER’
定义 mutation
[ADD_NUMBER](state,payload){state.counter += payload.count
}
提交mutation
$store.commit({type:ADD_NUMBER,count:100})
mapMutations辅助函数
-快速映射到对应的方法中:
methods:{...mapMutations({k:v}),...mapMutations(["",""])
}
在setup中使用方式:
const mutations = mapMutations(['','']);
const mutations-cs = mapMutations({k:v})
mutation重要原则
- 要求 必须是同步函数
会记录mutation的日记
每一条mutation被记录,devtools都需要捕捉到前一状态和后一状态的快照;
目的是可以追踪到数据的变化,如果发送网络请求的话需要如何操作
actions的基本使用
- Action类似于mutation,不同在于:
action提交的是mutation,而不是直接变更状态; - 另外重要的一点:action可以包含任意异步操作
actions:{increment(context){context.commit('increment') }
}
- 这里有一个重要的参数
context
context是一个和store实例具有相同方法和属性的context对象;
那我们就可以从其中获取到commit方法来提交一个mutation,或通过context.state和context.getters来获取state和getters; - 但是它和store对象有区别
actions
的分发
操作
- 如何使用action,进行内容分发 也可以携带参数
分发使用的是 store上的dispatch
函数;
submitbtn(){this.$store.dispatch("subbtn",{message:"111222"});
}
- 也可以对象的形式进行分发
submitbtn(){this.$store.dispatch({type:"",message:"", })
}
actions的辅助函数
- action也有对应的辅助函数:
对象类型方式:
数组类型方式:
methods:{...mapActions(['','']),...mapActions({k:v})
}
actions的异步操作
- 通常是异步的,监听什么时候结束呢
通过返回Promise,在Promise的then中处理完成后的操作
actions:{increment(context){return new Promise((res)=>{setTimeout(()=>{context.commit("increment")res("异步触发了")})})}
}
const store = useStore();
const increment = ()=>{store.dispatch("increment").then(res=>{console.log(res,"异步好了")})
}
module的基本使用
- Module的定义
由于使用单一状态树,应用的所有状态会集中到一个比较大的对象,随着复杂度递增,store对象变得很臃肿;
为了解决此问题,Vuex允许将store分割
每个分割的模块可以拥有自己的state/mutation/action/getter/嵌套子模块
const home= {state(){return {}},mutations:{},actions:{},getters:{}
},
const moduleB = {state:()=>({}),mutations:{},actions:{},getters:{}
}
const store = createStore({modules:{home:moduleA,b:moduleB}
})
store.state.home //home模块的状态
module的局部状态
-对于模块内部的 mutation和 getter,接收的第一个参数是 模块的局部状态对象
mutations:{//第二个参数 接收传递的数据increment(state,payload){console.log(store.state.counter);// 获取对象方式store.state.counter += payload.count },changeName(state){state.name = '局座高明'},changeBanner(state,banners){state.banners = banners}},
随着模块的增加 组件派发的方法名称增加,在仓库模块中需要格外小心如果都存在相同名称的方法, 名称是否冲突 那么能否
module的命名空间
- 默认情况下,模块内部的action和mutation是注册在全局的命名空间中的
- 这样使得多个模块能够对同一个 action或mutation作出响应
- Getter同样也默认注册在全局命名空间;
- 如果希望模块具有高度的封装度和复用性,可以添加配置项 namespaced:true 的方式使其成为带命名空间的模块;
当模块注册后,它的所有 getter/action/mutation都会自动根据模块注册的路径调整命名;