状态管理
我们会的应用程序需要处理各种各样的数据,这些数据需 要保存在我们应用程序中的某一个位置,对于这些数据的管理我们就 称之为是 状态管理。
在vue中都是组件式开发
- 在组件里面定义的data/setup中返回的使用的数据 称之为state
- 在template模版中使用 并且渲染成DOM 称之为view
- 模版中产生行为事件 处理这些行为事件 有可能会修改state 称之为actions
vuex和单纯的全局对象有什么区别
- vuex储存的状态是响应式的 当vue组件从store中读取状态的时候 若store中的state发生了改变 那么相对应的组件也会被更改
- 你不能直接改变store中的状态 改变store中的**状态唯一途径就是显示提交(commit)mutation **这样是我们可以方便的跟踪每一个状态的改变 从而让我们能够通过一些工具帮助我们更好的管理应用状态
单一状态树
vuex使用的是单一状态树 一个对象就包括了全部的应用层级的状态 单一状态树和模块化并不冲突
◼ 单一状态树的优势:
如果你的状态信息是保存到多个Store对象中的,那么之后的管理和维护等等都会变得特别困难;
所以Vuex也使用了单一状态树来管理应用层级的全部状态;
单一状态树能够让我们最直接的方式找到某个状态的片段;
而且在之后的维护和调试过程中,也可以非常方便的管理和维护;
辅助函数
mapState
vue2中使用
数组写法
...mapState(['映射的元素']) 他返回的是函数 所以需要展开运算符
对象写法。可以重命名
...mapState({
sName:state=>state.name
sAge:state=>state.age
})
然后需要在computed:{
...mapState({})
}
vue3中使用
如果在vue3中使用mapState的话 虚啊哟在computed调用该函数的时候 手动绑定一个this this的值就是{store:store}** 因为在vue3中是没有this的 所以在computed内部解析的时候 **无法通过this.store.state.name 来取值的 因为取不到this 所以这个时候需要手动绑定这个this
- 第一种方式 通过调用computed的时候 利用bind 绑定一个this
import { computed } from 'vue';
import { useStore, mapState } from 'vuex';
const store = useStore()
const {name,age}=mapState(['name','age'])
const cName = computed(name.bind({$store:store}))
- 第二种:封装一个hook
import { computed } from 'vue';
import { useStore, mapState } from 'vuex';
export default function useState(mapper){
const store= useStore
const stateFnsObj = mapState(mapper)
const newState={}
Object.keys(stateFnsObj).forEach((item,key)=>{
newState[key]=computed(stateFnsObj[item].bind({$store:store}))
})
return newState
}
import { useStore } from 'vuex';
因为这块返回的是一个computed 所以及时结构里 但是还是响应式的
const { name, age } = useStore(['name', 'age'])
- 第三种直接对store.state进行解构
const store=useStore()
const {name:sName='111',age}=toRefs(store.state)
getters
getters: {
基本使用 而且第二个参数可以获取其他getters的函数
doubolCounter(state, getters) {
return state * 2;
},
也可以返回一个函数
getFridenById(state) {
return function (id) {
return state.friend.find(item => item.id === id);
};
},
},
mutations
mutations: {
// 这块可以使用一个常量 ADD_MumBer定义一个常量 用的对象的计算属性[一个变量]
// [ADD_MumBer](state){state.counter}
increment(state) {
state.counter++;
},
},
可以在template里面调用引入的函数
methods:{
changName(){
this.$store.commit('increment','www')
}
...mapMutations(['changeName','increnentievel'])
}
actions
actions提交的是mutation 而不是直接修改状态 因为在vuex里面 它所有的修改状态state的值都是通过mutation的 它可以进行任意异步操作 context是一个和store实例均有相同方法和属性的context对象;所以我们可以从其中获取到commit方法来提交一个mutation,或者通过 context.state 和 context.getters 来获取 state 和getters **可以在actions中的异步函数调用一个promise 这样就可以在dispatch中监听是否异步函数执行完毕 **
actions: {
incremen(context) {
context.commit('increment');
return new Promise(async (resolve, reject) => {
const data = await '调用请求返回的值';
resolve(data);
});
},
},
modules
- 由于使用单一状态树,应用的所有状态会集中到一个比较大的对象,当应用变得非常复杂时,store 对象就有可能变得相当臃
- 为了解决以上问题,Vuex 允许我们将 store 分割成模块(module);
- 每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块;
- 在获取state的时候需要store.home.message 在模块化中 actions/getters/mutations 他都默认合并在store里面
- **namespaced: true **模块抽离出来的代码是否有命名空间 这样的话actions/getters/mutations 使用的话需要语法糖$store.getters["counter模块/doubleCount方法"]
- 在store.dispatch("counter模块/doubleCount方法") 如果我们需要在action里面修改root的state
pinia
本质:pinia 最初是为了探索 vuex 的下一次迭代会是啥样的 结合了vuex5核心团队的想法 最终团队意识到了pinia已经实现了vuex5中的大部分内容 最终选择了pinia代替了vuex
与vuex相比
- pinia提供了更简单的api 具有更少的仪式感 提供了堆compositionAPI的支持
- 重要的是 与ts 一起使用时候具有可靠的类型推断支持
- mutation将不再存在 **它们经常认为这个操作是非常鸡肋的 pinia也提供了devtools的集成 **
- 更友善的ts支持
- 不再有modules的嵌套结构
- 可以灵活使用每一个store 它们是通过扁平化的方式来互相使用 它们都是互相独立的
- 也不再有命名空间的概念 不需要记住他们的复杂关系
定义store
需要通过defineStore('store名称 这个是连接devtools的标识',{}) 返回函数统一用useX命名 当你再次调用它的时候 他就返回时当前定义的store
- 在获取数据的解构赋值的时候 可以通过vue的toRefs包裹 或者用pinia的storeToRefs来包裹进行数据响应式处理
- store 中也有this 这个this就是当前store的实例
- state 其实就是相当于组件的data
- getters 其实就是相当于组件的computed 并且他可以直接使用this
- actions 其实就是相当于组件中的methods 适合定义业务逻辑 并且也可以使用this
import { useCounter } from '../stores/counter';
import { defineStore } from 'pinia';
const useCounter = defineStore('counter', {
state: () => {
message: 111;
},
getters: {
//1.
doubleCount(state) {
return state.message * 2;
},
// 2.引入另一个getter
doubleCou1nt(state) {
return this.doubleCount + 1;
},
// 3.返回一个函数
getFriendByid(state) {
return function (id) {
return state.message === id;
};
},
// 使用到其他模块的getters
showMessage(state) {
// 获取到user的信息
const userStore = useCounter();
// 获取到自己的信息
// 拼接信息
return `name:${userStore.name}-count:${state.message}`;
},
},
actions: {
increment() {},
},
});
在调用/操作的时候
const consterStore = useCounter()
const { message } = storeToRefs(consterStore)
// 可以直接进行修改state的值
consterStore.message = 299
// $reset 恢复初始化数值 因为在他初始化的时候 有过缓存保存过的
consterStore.$reset()
// $patch 一次性修改多个状态
useCounter.$patch({
message: 222,
name: '3123'
})
// 直接替换整个store
useCounter.$state = {
name: '3213',
age: '312312'
}