目录
一、概念
vue2 契合 vuex | vue3 契合 pinia
1. 状态管理
在开发中,应用程序需要处理各种各样的数据,这些数据需要保存在应用程序中的某一个位置,对于这些数据的管理就称之为是状态管理
- 在Vue开发中,使用组件化的开发方式
- 而在组件中定义data或者在setup中返回使用的数据,这些数
据称之为state - 在模块template中可以使用这些数据,模块最终会被渲染成
DOM,称之为View - 在模块中会产生一些行为事件,处理这些行为事件时,有可能
会修改state,这些行为事件称之为actions
2. Vuex的状态管理
- 可以考虑将组件的内部状态抽离出来,以一个全局单例的方式来管理
- 在这种模式下,组件树构成了一个巨大的 “试图View”
- 不管在树的哪个位置,任何组件都能获取状态或者触发行为
- 通过定义和隔离状态管理中的各个概念,并通过强制性的规则来维护视图和状态间的独立性,代码会变得更加结构化和易于维护、跟踪
3. 单一状态树
Vuex 使用单一状态树 :
- 用一个对象就包含了全部的应用层级的状态
- 采用的是SSOT,Single Source of Truth,也可以翻译成单一数据源
- 每个应用将仅仅包含一个 store 实例
- 单状态树和模块化并不冲突,可以使用module模块
单一状态树的优势 :
- 如果状态信息是保存到多个Store对象中的,那么之后的管理和维护等等都会变得特别困难
- 所以Vuex使用了单一状态树来管理应用层级的全部状态
- 单一状态树能够让我们最直接的方式找到某个状态的片段
- 而且在之后的维护和调试过程中,也可以非常方便的管理和维护
单一状态树的缺点 : 不够灵活
二、Vuex 的基本使用
1. Vuex的安装
npm install vuex
2. 创建store
每一个Vuex应用的核心就是store(仓库)
store本质上是一个容器,它包含着你的应用中大部分的状态(state)
Vuex和单纯的全局对象的区别 :
- 第一:Vuex的状态存储是响应式的
- 当Vue组件从store中读取状态的时候,若store中的状态发生变化,那么相应的组件也会被更新
- 第二:不能直接改变store中的状态
- 改变store中的状态的唯一途径就显示提交 (commit) mutation
- 这样使得我们可以方便的跟踪每一个状态的变化,从而让我们能够通过一些工具帮助我们更好的管理应用的状态
3. 在store文件夹下创建index.js
// 1. 引入
import { createStore } from 'vuex';
// 2. 创建store对象
const store = createStore({
// 3. 定义state
state: () => ({
// 4. 定义数据
count: 100
}),
// 5. 定义mutations
mutations: {
// 6. 定义方法
increment(state) {
state.count++;
}
}
});
// 5. 导出
export default store;
4. 在main.js中引入
import { createApp } from 'vue';
import App from './App.vue';
// 1. 导入
import store from './store';
// 2. 使用
createApp(App).use(store).mount('#app');
5. 组件中使用sotre
<template>
<div class="app">App 页面</div>
<!-- 1. 模版中使用 -->
<h2>模版 : {{ $store.state.count }}</h2>
<h2>computed : {{ storeCount }}</h2>
<h2>解构count : {{ count }}</h2>
<button @click="btnClick">增加</button>
</template>
<script setup>
// 2. 在js中使用
import { useStore } from 'vuex';
import { computed, toRefs } from 'vue';
const store = useStore();
console.log(store.state.count);
// 01 - computed包裹一下变成响应式
const storeCount = computed(() => store.state.count);
// 02 - 解构成ref对象
const { count } = toRefs(store.state);
// 监听按钮的点击
const btnClick = () => {
// 触发mutation,让count++
store.commit('increment');
};
</script>
6. 效果
三、核心概念 State
1. 直接使用
<template>
<div class="app">App 页面</div>
<!-- 1. 模版中使用 -->
<h2>模版 : {{ $store.state.count }}</h2>
<h2>computed : {{ storeCount }}</h2>
<h2>解构count : {{ count }}</h2>
</template>
<script setup>
// 2. 在js中使用
import { useStore } from 'vuex';
import { computed, toRefs } from 'vue';
const store = useStore();
console.log(store.state.count);
// 01 - computed包裹一下变成响应式
const storeCount = computed(() => store.state.count);
// 02 - 解构成ref对象
const { count } = toRefs(store.state);
</script>
2. mapState
vue3 使用 map之类的,比较麻烦
01 - 使用
<template>
<div class="app">App 页面</div>
<h2>模版 : {{ $store.state.count }}</h2>
<h2>mapState : {{ cCount }}</h2>
<button @click="btnClick">改变</button>
</template>
<script setup>
import { useStore, mapState } from 'vuex';
import { computed } from 'vue';
// 1. 拿到store对象
const store = useStore();
// 2. 使用mapState解构出方法
// const { count } = mapState(['count']);
// 数组和对象都可以
const { count } = mapState({
count: (state) => state.count
});
// 3. 拿到对应的值
/**
* count => 底层还是通过this.$store.state.count去拿的
* 因为 setup 中没有this,所以传递过去时需要显示绑定一个$store
*/
const cCount = computed(count.bind({ $store: store }));
const btnClick = () => {
store.commit('increment');
};
</script>
02 - 封装
useState.js
import { useStore, mapState } from 'vuex';
import { computed } from 'vue';
export default function useState(mapper) {
// 1. 拿到store对象
const store = useStore();
// 2. 使用mapState拿到对应的方法
const stateFnsObj = mapState(mapper);
// 4. 定一个接受对象
const newState = {};
// 5.遍历
Object.keys(stateFnsObj).forEach((key) => {
// 6. 生成绑定过的对象
newState[key] = computed(stateFnsObj[key].bind({ $store: store }));
});
// 7. 返回
return newState;
}
使用
<template>
<div class="app">App 页面</div>
<h2>模版 : {{ $store.state.count }}</h2>
<!-- 3. 展示 -->
<h2>封装哒 : {{ fCount }}</h2>
<button @click="btnClick">改变</button>
</template>
<script setup>
import { useStore } from 'vuex';
// 1. 导入封装的方法
import useState from './hooks/useState';
// 2. 使用
const { count: fCount } = useState(['count']);
const store = useStore();
const btnClick = () => {
store.commit('increment');
};
</script>
四、核心概念 Getters
1. 基本使用
代码
import { createStore } from 'vuex';
const store = createStore({
state: () => ({
count: 100
}),
mutations: {
increment(state) {
state.count++;
}
},
// 定义getters
getters: {
doubleCount(state) {
return state.count * 2;
}
}
});
export default store;
使用
<template>
<div class="app">App 页面</div>
<h2>模版 : {{ $store.state.count }}</h2>
<!-- 使用getters -->
<h2>doubleCount : {{ $store.getters.doubleCount }}</h2>
<button @click="btnClick">改变</button>
</template>
<script setup>
import { useStore } from 'vuex';
const store = useStore();
const btnClick = () => {
store.commit('increment');
};
</script>
2. getters第二个参数
getters可以接收第二个参数,用来调用其他的getters
代码
import { createStore } from 'vuex';
const store = createStore({
state: () => ({
count: 100
}),
mutations: {
increment(state) {
state.count++;
}
},
getters: {
doubleCount(state, getters) {
// 可以调用其他的getters函数
return state.count * 2 + getters.mathRanDom;
},
// 生成[5,50)的随机数
mathRanDom() {
return Math.floor(Math.random() * 45) + 5;
}
}
});
export default store;
使用
<template>
<div class="app">App 页面</div>
<h2>模版 : {{ $store.state.count }}</h2>
<h2>random : {{ $store.getters.mathRanDom }}</h2>
<!-- 使用getters -->
<h2>doubleCount : {{ $store.getters.doubleCount }}</h2>
<button @click="btnClick">改变</button>
</template>
<script setup>
import { useStore } from 'vuex';
const store = useStore();
const btnClick = () => {
store.commit('increment');
};
</script>
3. getters的返回函数
getters中的函数本身,可以返回一个函数,可用来接受参数
代码
import { createStore } from 'vuex';
const store = createStore({
state: () => ({
count: 100
}),
mutations: {
increment(state) {
state.count++;
}
},
getters: {
doubleCount(state, getters) {
// 可以调用其他的getters函数
return state.count * 2 + getters.mathRanDom;
},
// 生成[5,50)的随机数
mathRanDom() {
return Math.floor(Math.random() * 45) + 5;
},
countAddNum(state) {
// 可用来接受传进来的参数
return function (num) {
return state.count + num;
};
}
}
});
export default store;
使用
<template>
<div class="app">App 页面</div>
<h2>模版 : {{ $store.state.count }}</h2>
<!-- 基本使用getters -->
<h2>doubleCount : {{ $store.getters.doubleCount }}</h2>
<!-- 随机数 -->
<h2>random : {{ $store.getters.mathRanDom }}</h2>
<!-- 传递参数 -->
<h3>countAddNum : {{ $store.getters.countAddNum(10) }}</h3>
<h3>countAddNum : {{ $store.getters.countAddNum(20) }}</h3>
<button @click="btnClick">改变</button>
</template>
<script setup>
import { useStore } from 'vuex';
const store = useStore();
const btnClick = () => {
store.commit('increment');
};
</script>
4. mapGetters
<template>
<div class="app">App 页面</div>
<h2>{{ doubleCount }}</h2>
<button @click="btnClick">改变</button>
</template>
<script setup>
import { computed, toRefs, watch, watchEffect } from 'vue';
import { useStore, mapGetters } from 'vuex';
const store = useStore();
// 1. 第一种方法
// const { doubleCount } = toRefs(store.getters);
// 2. 第二种方法
// const doubleCount = computed(() => store.getters.doubleCount);
// 3. 第三种方法,使用mapGetters
const { doubleCount: doubleCountFn } = mapGetters(['doubleCount']);
const doubleCount = computed(doubleCountFn.bind({ $store: store }));
// 这样时时打印数据
watchEffect(() => {
console.log(doubleCount.value);
});
const btnClick = () => {
store.commit('increment');
};
</script>
五、核心概念 Mutations
六、核心概念 Actions
七、核心概念 Modules
本文含有隐藏内容,请 开通VIP 后查看