
目录
vue2 契合 vuex | vue3 契合 pinia
在开发中,应用程序需要处理各种各样的数据,这些数据需要保存在应用程序中的某一个位置,对于这些数据的管理就称之为是状态管理


Vuex 使用单一状态树 :
单一状态树的优势 :
单一状态树的缺点 : 不够灵活
npm install vuex
每一个Vuex应用的核心就是store(仓库)
store本质上是一个容器,它包含着你的应用中大部分的状态(state)
Vuex和单纯的全局对象的区别 :
- // 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;
- import { createApp } from 'vue';
- import App from './App.vue';
- // 1. 导入
- import store from './store';
- // 2. 使用
- createApp(App).use(store).mount('#app');
- <template>
- <div class="app">App 页面div>
-
- <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>

- <template>
- <div class="app">App 页面div>
-
- <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>
- <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
- *
- * 通过显示绑定bind对象,让this指向这个对象
- * 然后底层就能拿到this.$store了
- */
- const cCount = computed(count.bind({ $store: store }));
-
- const btnClick = () => {
- store.commit('increment');
- };
- script>
- 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>
-
- <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>
- 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>
-
- <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>
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>
-
-
- <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>
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>
-
-
- <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>
- <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>
- import { useStore, mapGetters } from 'vuex';
- import { computed } from 'vue';
-
- export default function useGetters(mapper) {
- const store = useStore();
- // 1. 接受全部getters
- const gettersFn = mapGetters(mapper);
- // 2. 定义新的函数数组
- const newGetters = {};
- // 3. 遍历绑定
- Object.keys(gettersFn).forEach((key) => {
- newGetters[key] = computed(gettersFn[key].bind({ $store: store }));
- });
- // 返沪
- return newGetters;
- }
- <template>
- <div class="app">App 页面div>
-
- <h2>{{ doubleCount }}h2>
-
- <button @click="btnClick">改变button>
- template>
-
- <script setup>
- import { watchEffect } from 'vue';
- import { useStore } from 'vuex';
- // 1. 导入
- import useGetters from '@/hooks/useGetters';
-
- // 2. 使用
- const { doubleCount } = useGetters(['doubleCount']);
-
- const store = useStore();
- const btnClick = () => {
- store.commit('increment');
- };
- // 这样时时打印数据
- watchEffect(() => {
- console.log(doubleCount.value);
- });
- script>
更改 Vuex 的 store 中的状态的唯一方法是提交 mutation
mutation 必须是同步函数
- import { createStore } from 'vuex';
-
- const store = createStore({
- state: () => ({
- count: 100
- }),
- mutations: {
- increment(state) {
- state.count++;
- }
- }
- });
-
- export default store;
- <template>
- <div class="app">App 页面div>
-
- <h2>{{ $store.state.count }}h2>
-
- <button @click="btnClick">改变button>
- template>
-
- <script setup>
- import { useStore } from 'vuex';
-
- const store = useStore();
- const btnClick = () => {
- // 使用mutation中定义的方法
- store.commit('increment');
- };
- script>
- import { createStore } from 'vuex';
-
- const store = createStore({
- state: () => ({
- count: 100
- }),
- mutations: {
- // 接受传递过来的参数
- increment(state, num) {
- state.count += num;
- }
- }
- });
-
- export default store;
- <template>
- <div class="app">App 页面div>
-
- <h2>{{ $store.state.count }}h2>
-
- <button @click="btnClick">改变button>
- template>
-
- <script setup>
- import { useStore } from 'vuex';
-
- const store = useStore();
- const btnClick = () => {
- // 传递数据
- store.commit('increment', 10);
- };
- script>
- // 定义成常量类型
- export const INCREMENT = 'increment';
- import { createStore } from 'vuex';
- // 1. 导入
- import { INCREMENT } from './mutation_types';
-
- const store = createStore({
- state: () => ({
- count: 100
- }),
- mutations: {
- // 2. 使用常量作为名称,使用计算属性值
- [INCREMENT](state, num) {
- state.count += num;
- }
- }
- });
-
- export default store;
- <template>
- <div class="app">App 页面div>
-
- <h2>{{ $store.state.count }}h2>
-
- <button @click="btnClick">改变button>
- template>
-
- <script setup>
- import { useStore } from 'vuex';
- // 1. 导入
- import { INCREMENT } from '@/store/mutation_types';
-
- const store = useStore();
- const btnClick = () => {
- // 2. 使用
- store.commit(INCREMENT, 10);
- };
- script>
- <template>
- <div class="app">App 页面div>
-
- <h2>{{ $store.state.count }}h2>
-
- <button @click="btnClick">改变button>
- template>
-
- <script setup>
- import { useStore, mapMutations } from 'vuex';
- import { INCREMENT } from '@/store/mutation_types';
-
- const store = useStore();
-
- // 1. 接受全部函数
- const mutationFns = mapMutations([INCREMENT]);
- // 2. 定义新的函数数组
- const newMutations = {};
- // 3. 遍历绑定
- Object.keys(mutationFns).forEach((key) => {
- newMutations[key] = mutationFns[key].bind({ $store: store });
- });
- // 4. 从新生成的函数数组中解构出来
- const { increment } = newMutations;
- const btnClick = () => {
- // 5. 使用
- increment(10);
- };
- script>
- import { useStore, mapMutations } from 'vuex';
-
- export default function useMutations(mapper) {
- const store = useStore();
- // 1. 接受全部函数
- const mutationFns = mapMutations(mapper);
- // 2. 定义新的函数数组
- const newMutations = {};
- // 3. 遍历绑定
- Object.keys(mutationFns).forEach((key) => {
- newMutations[key] = mutationFns[key].bind({ $store: store });
- });
- // 返回对象
- return newMutations;
- }
- <script setup>
- import { useStore, mapMutations } from 'vuex';
- // 1. 导入
- import useMutations from '@/hooks/useMutations';
- // 2. 解构
- const { increment } = useMutations(['increment']);
- const btnClick = () => {
- // 3. 使用
- increment(10);
- };
- script>
Action类似于mutation
参数context :
- import { createStore } from 'vuex';
-
- const store = createStore({
- state: () => ({
- count: 100
- }),
- mutations: {
- increment(state) {
- state.count++;
- }
- },
- getters: {
- doubleCount(state, getters) {
- return state.count * 2 + getters.mathRanDom;
- },
- mathRanDom() {
- return Math.floor(Math.random() * 45) + 5;
- }
- },
- actions: {
- // 定义actions方法
- incrementAction(context) {
- // 1. 可进行接口请求
- // balabalabala~
- // 2. 通过mutation来修改state的状态
- context.commit('increment');
- }
- }
- });
-
- export default store;
- <template>
- <div class="app">App 页面div>
-
- <h2>{{ $store.state.count }}h2>
-
- <button @click="btnClick">改变button>
- template>
-
- <script setup>
- import { watchEffect } from 'vue';
- import { useStore } from 'vuex';
-
- const store = useStore();
-
- const btnClick = () => {
- // 调用action方法
- store.dispatch('incrementAction');
- };
- script>
- import { createStore } from 'vuex';
-
- const store = createStore({
- state: () => ({
- count: 100
- }),
- mutations: {
- increment(state, num = 10) {
- state.count += num;
- }
- },
- getters: {
- doubleCount(state, getters) {
- return state.count * 2 + getters.mathRanDom;
- },
- mathRanDom() {
- return Math.floor(Math.random() * 45) + 5;
- }
- },
- actions: {
- // 定义actions方法,接受参数
- incrementAction(context, num) {
- // 调用mutations方法
- context.commit('increment', num);
- }
- }
- });
-
- export default store;
- <template>
- <div class="app">App 页面div>
-
- <h2>{{ $store.state.count }}h2>
-
- <button @click="btnClick">改变button>
- template>
-
- <script setup>
- import { watchEffect } from 'vue';
- import { useStore } from 'vuex';
-
- const store = useStore();
-
- const btnClick = () => {
- // 调用action方法,传递参数
- store.dispatch('incrementAction', 9);
- };
- script>
- <template>
- <div class="app">App 页面div>
-
- <h2>{{ $store.state.count }}h2>
-
- <button @click="btnClick">改变button>
- template>
-
- <script setup>
- import { watchEffect } from 'vue';
- import { useStore, mapActions } from 'vuex';
-
- const store = useStore();
- // 1. 接受全部的actions
- const actionsFn = mapActions(['incrementAction']);
- // 2. 定义新的actions对象
- const newActions = {};
- // 3. 遍历
- Object.keys(actionsFn).forEach((key) => {
- newActions[key] = actionsFn[key].bind({ $store: store });
- });
- // 4. 解构
- const { incrementAction } = newActions;
- const btnClick = () => {
- // 5. 使用
- incrementAction(9);
- };
- script>
- import { useStore, mapActions } from 'vuex';
-
- export default function useActions(mapper) {
- const store = useStore();
- // 1. 接受全部的actions
- const actionsFn = mapActions(['incrementAction']);
- // 2. 定义新的actions对象
- const newActions = {};
- // 3. 遍历
- Object.keys(actionsFn).forEach((key) => {
- newActions[key] = actionsFn[key].bind({ $store: store });
- });
- return newActions;
- }
- <template>
- <div class="app">App 页面div>
-
- <h2>{{ $store.state.count }}h2>
-
- <button @click="btnClick">改变button>
- template>
-
- <script setup>
- import { watchEffect } from 'vue';
- import { useStore, mapActions } from 'vuex';
- // 1. 导入
- import useActions from '@/hooks/useActions';
- // 2. 解构
- const { incrementAction } = useActions(['incrementAction']);
- const btnClick = () => {
- // 5. 使用
- incrementAction(9);
- };
- script>
- import { createStore } from 'vuex';
-
- const store = createStore({
- state: () => ({
- // 1. 保存请求来的数据
- arrayList: []
- }),
- mutations: {
- // 2. 保存数据到 arrayList 中
- saveArrayList(state, list) {
- state.arrayList = list;
- }
- },
- actions: {
- // 3. 定义异步请求actions
- async fetchDataList(context) {
- /**
- * 1. 请求
- */
- // fetch('http://xxxx').then((res) => {
- // res.json().then((data) => {
- // console.log(data);
- // context.commit('saveArrayList', data.list);
- // });
- // });
-
- /**
- * 2. 优化,Promise链式调用
- */
- // fetch('http://xxxx')
- // .then((res) => {
- // return res.json();
- // })
- // .then((data) => {
- // console.log(data);
- // context.commit('saveArrayList', data.list);
- // });
-
- /**
- * 3. 使用async await
- */
- // const res = await fetch('http://xxxx');
- // const data = await res.json();
- // context.commit('saveArrayList', data.list);
-
- /**
- * 4. 模拟,并返回一个promise
- */
- return new Promise((resolve) => {
- setTimeout(() => {
- const data = [1, 2, 3, 4, 5];
- // 保存在state中
- context.commit('saveArrayList', data);
- // 把数据返回出去
- resolve(data);
- }, 1000);
- });
- }
- }
- });
-
- export default store;
- <template>
- <div class="app">App 页面div>
-
- <h2>{{ dataList }}h2>
-
- <h2>{{ $store.state.arrayList }}h2>
-
- <h2>h2>
- template>
-
- <script setup>
- import { ref } from 'vue';
- import { useStore } from 'vuex';
-
- const store = useStore();
- const dataList = ref([]);
- // 1. 调用dispatch方法,请求数据
- store.dispatch('fetchDataList').then((res) => {
- // 2. 拿到数据
- dataList.value = res;
- console.log(res);
- });
- script>
Module :
state : 使用的时候需要在前面加上模块的名称
mutation、getters、action : 默认集成在顶层中,可直接使用
ps : 所以,state可以定义相同的名字,但是其他的重名会报错,命名冲突问题
- export default {
- // 模块数据
- state: () => ({
- m_Age: 18
- }),
- // 模块方法
- mutations: {
- // state => 指的是本模块的数据
- m_AddAge(state) {
- state.m_Age++;
- }
- },
- // 模块action
- actions: {
- /**
- * state => 指的是本模块的数据
- * commit => 可调用所有方法
- * rootState => 指的是根模块的数据
- */
- m_AddAgeAction({ state, commit, rootState }) {
- // 调用本模块方法
- commit('m_AddAge');
- // 调用根模块方法
- commit('increment');
- }
- },
- // 模块action
- getters: {
- /**
- * state => 指的是本模块的数据
- * getters => 可调用所有getters
- * rootState => 指的是根模块的数据
- */
- getMAge(state, getters, rootState) {
- return state.m_Age;
- }
- }
- };
- import { createStore } from 'vuex';
- // 1.导入模块
- import moduleA from './moduleA';
-
- const store = createStore({
- state: () => ({
- count: 100
- }),
- mutations: {
- increment(state) {
- state.count++;
- }
- },
- actions: {
- incrementAction({ commit }) {
- commit('increment');
- }
- },
- getters: {
- getCount(state) {
- return state.count;
- }
- },
- // 2. 注册一下
- modules: {
- moduleA
- }
- });
-
- export default store;
- <template>
- <div class="app">App 页面div>
- <h2>根目录 :h2>
- count : {{ $store.state.count }}<br />
- count : {{ $store.getters.getCount }}
- <hr />
- <hr />
- <hr />
- <h2>模块目录 :h2>
- m_Age : {{ $store.state.moduleA.m_Age }} <br />
- m_Age : {{ $store.getters.getMAge }}
- template>
-
- <script setup>
- import { ref, computed } from 'vue';
- import { useStore } from 'vuex';
-
- const store = useStore();
- /**
- * 调用根模块
- */
- // state
- const count = computed(() => store.state.count);
- console.log('count', count.value);
- // getters
- const getCount = computed(() => store.getters.getCount);
- console.log('getMAge', getCount.value);
- // mutation
- store.commit('increment');
- // action
- store.dispatch('incrementAction');
-
- /**
- * 调用模块内
- */
- // state
- const m_Age = computed(() => store.state.moduleA.m_Age);
- console.log('m_Age', m_Age.value);
- // getters
- const getMAge = computed(() => store.getters.getMAge);
- console.log('getMAge', getMAge.value);
- // mutation
- store.commit('m_AddAge');
- // action
- store.dispatch('m_AddAgeAction');
- script>
默认情况下,模块内部的action、mutation、getters仍然是注册在全局的命名空间中的 :
如果希望模块具有更高的封装度和复用性
- export default {
- // 加上这个属性
- namespaced: true,
- state: () => ({
- m_Age: 18
- }),
- ......
- };
- <template>
- <div class="app">App 页面div>
- <h2>根目录 :h2>
- count : {{ $store.state.count }}<br />
- count : {{ $store.getters.getCount }}
- <hr />
- <hr />
- <hr />
- <h2>模块目录 :h2>
- m_Age : {{ $store.state.moduleA.m_Age }} <br />
- m_Age : {{ $store.getters['moduleA/getMAge'] }}
- template>
-
- <script setup>
- import { ref, computed } from 'vue';
- import { useStore } from 'vuex';
-
- const store = useStore();
- /**
- * 调用根模块
- */
- // state
- const count = computed(() => store.state.count);
- console.log('count', count.value);
- // getters
- const getCount = computed(() => store.getters.getCount);
- console.log('getMAge', getCount.value);
- // mutation
- store.commit('increment');
- // action
- store.dispatch('incrementAction');
-
- /**
- * 调用模块内
- */
- // state
- const m_Age = computed(() => store.state.moduleA.m_Age);
- console.log('m_Age', m_Age.value);
- // getters
- const getMAge = computed(() => store.getters['moduleA/getMAge']);
- console.log('getMAge', getMAge.value);
- // mutation
- store.commit('moduleA/m_AddAge');
- // action
- store.dispatch('moduleA/m_AddAgeAction');
- script>
如果希望在action中修改root中的state
