十二、 Vuex 状态管理

本文详细介绍了Vuex的状态管理模式,包括Vuex的基本概念、如何创建和使用Vuex store、通过mutations和actions修改状态、利用getters创建派生状态以及模块化的项目结构。通过实例演示了Vuex在Vue项目中的应用,如在不同组件间共享和修改状态,展示了Vuex在管理复杂应用状态中的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、Vuex 概述

1. 官方文档:https://vuex.vuejs.org/zh/Vuex 是一个专为 Vue.js 应用程序开发的状态管理模式。它采用集中式存储管理应用的所有组件的状态,并以相应的规则保证状态以一种可预测的方式发生变化。

2. Vuex简单理解: Vue 应用中的每个组件在 data() 中封装着自己数据属性,而这些 data 属性都是私有的,完全隔离的。 如果我们希望多个组件都能读取到同一状态数据属性,或者不同组件的行为需要更新同一状态数据属 性, 这就需要一个将共享的状态数据属性进行集中式的管理。 这就是 Vuex 状态管理所要解决的问题。

3.上面复制的,我写不出这么深刻的理解。

二、整整试试

1.先创建一个Vue项目,手动安装,vuex Router ,2.x版本然后一顿回车,哈哈哈

2.然后运行一下服务

3.面试爱问:每一个 Vuex 应用的核心就是 store(仓库)

4.在store文件下的index.js中添加 count: 0:

export default new Vuex.Store({
    state: {
        count: 0
    },
    mutations: {},
    actions: {},
    modules: {}
})

5.然后让他在页面中显示,找到views的home.vue:

<template>
  <div class="home">
     <h1>1111</h1>
    <HelloWorld msg="Welcome to Your Vue.js App"/>
  </div>
</template>

6.效果:

7.用{{$store.state}}来获取状态对象,

<template>
  <div class="home">
     <h1>{{$store.state.count}}</h1>
    <HelloWorld msg="Welcome to Your Vue.js App"/>
  </div>
</template>

8.效果:

 9.我们可以改变一下这个值count,通过mutations,回到store文件下的index.js中:

 mutations: {
        increment(state) {
            state.count++
        },
        decrement(state) {
            state.count--
        }
    },

10.再回到views的home.vue:

<template>
  <div class="home">
     <h1>{{$store.state.count}}</h1>
     <button @click="add">++</button>
     <button @click="decrement">--</button>
    <HelloWorld msg="Welcome to Your Vue.js App"/>
  </div>
</template>

11.在export default里添加方法:

export default {
  name: "Home",
  components: {
    HelloWorld,
  },
  methods: {
    add() {

      
    },
    decrement() {},
  },
};

12.官网--可以从组件的方法提交一个变更-----this.$store.commit:

methods: {
    add() {
      this.$store.commit("increment");
    },
    decrement() {
      this.$store.commit("decrement");
    },
  },

13.现在可以实现点击++时,0++,点击--时,0--

14.就像官网所说,store当成一个仓库,然后通过在组件中去调用它的内部的方法,来实现对它的改动。

三、试试奥----mutation

更改 Vuex 的 store 中的状态的唯一方法是提交 mutation,不能直接调用一个 mutation,需要以相应的 type 调用 store.commit 方法

1.那么,我们可不可以在其他组件中使用它呢,在views的about.vue中,

<template>
  <div class="about">
     <h1>{{ $store.state.count }}</h1>
  </div>
</template>

2.结果发现也能拿到。

3.那么,我们可不可以在添加一个新值呢,加一个n,回到store文件下的index.js中:

 mutations: {
        increment(state, n) {
            state.count += n
        },
        decrement(state) {
            state.count--
        }
    },

在回到views的home.vue:

 methods: {
    add() {
      this.$store.commit("increment",10);
    },
    decrement() {
      this.$store.commit("decrement");
    },
  },

4.结果发现也能拿到。这叫载荷,可以向 store.commit 传入额外的参数,即 mutation 的 载荷(payload)

四、Action

Action 类似于 mutation,不同在于:

  • Action 提交的是 mutation,而不是直接变更状态。
  • Action 可以包含任意异步操作。

1.在store文件下的index.js中:

    actions: {
        dec({ commit }) {
            commit("decrement")
        },
    },

2.在组件中使用 this.$store.dispatch('xxx') 分发 action,在回到views的home.vue:

decrement() {
      // this.$store.commit("decrement");
       this.$store.dispatch('dec')
    },

3.测试可以实现减操作。

4.在Action中,结构赋值形式添加一个新值,在store文件下的index.js中:

add({ commit }) {
            commit("increment", 10)
        }

在回到views的home.vue:

 add() {
      // this.$store.commit("increment",10);
       this.$store.dispatch('add')
    },

5.测试可以实现加10操作。

6.默认形式添加一个新值,在store文件下的index.js中,把原来的add()注释上,添加:

 add(contxt) {
            contxt.commit("increment", 10)
        }

7.测试发现也可以实现加10操作。

五、 派生属性 getter

1. 理解 :

有时候我们需要从 store 中的 state 中派生出一些状态。例如:基于上面代码,增加一个 desc 属性,当 count 值小于 50,则 desc 值为 吃饭 ; 大于等于 50 小于100,则desc 值为 睡觉 ; 大于100 , 则 desc 值为 打豆豆 。这时我们就需要用到 getter 为我们解决。getter 其实就类似于计算属性(get)的对象.组件中读取 $store.getters.xxx 

2.实操

修改 store\index.js ,增加 getters 选项注意:getters 中接受 state 作为其第一个参数,也可以接受其他 getter 作为第二个参数

getters: {
        desc(state) {
            if (state.count < 50) {
                return "吃饭"
            } else if (state.count < 100) {
                return "睡觉"
            } else {
                return "打豆豆"
            }
        }
    }

修改 views\Home.vue, 显示派生属性的值:

<template>
  <div class="home">
    <h1>{{ $store.state.count }}</h1>
    <h2>{{$store.getters.desc}}</h2>
    <button @click="add">++</button>
    <button @click="decrement">--</button>
    <HelloWorld msg="Welcome to Your Vue.js App" />
  </div>
</template>

3.效果:

 

六、Module模块化项目结构

由于使用单一状态树,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter 等,参见以下代码模型 

const moduleA = {  

state: { ... },   mutations: { ... },   actions: { ... },   getters: { ... }

 }  

const moduleB = {  

state: { ... },   mutations: { ... },   actions: { ... }

 }  

const store = new Vuex.Store({   modules: {   a: moduleA,   b: moduleB  }  })

store.state.a // -> moduleA 的状态

store.state.b // -> moduleB 的状态

1.举个例子,修改 store\index.js:

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

let A = {
    state: {
        count: 0
    }, //存值

    // 下面都是方法
    mutations: {
        increment(state, n) {
            state.count += n
        },
        decrement(state, n) {
            state.count -= n
        }
    },
    actions: {
        dec({ commit }) {
            commit("decrement", 10)
        },
        // add({ commit }) {
        //     commit("increment", 10)
        // },
        add(contxt) {
            contxt.commit("increment", 10)
        }
    },
    getters: {
        desc(state) {
            if (state.count < 50) {
                return "吃饭"
            } else if (state.count < 100) {
                return "睡觉"
            } else {
                return "打豆豆"
            }
        }
    }
}



export default new Vuex.Store({

    modules: {
        a: A
    },

})

2.修改views\Home.vue:

<template>
  <div class="home">
    <h1>{{ $store.state.count }}</h1>
    <h2>{{$store.getters.desc}}</h2>
    <h3>{{$store.state.a.count}}</h3>
    <button @click="add">++</button>
    <button @click="decrement">--</button>
    <HelloWorld msg="Welcome to Your Vue.js App" />
  </div>
</template>

3.效果:

 4.为了保证变量重复的情况下也能使用,我们在index.js中引入,使它变成局部作用:

namespaced: true,

5.在home.vue中:

methods: {
    add() {
      // this.$store.commit("increment",10);
       this.$store.dispatch('a/add')
    },
    decrement() {
      // this.$store.commit("decrement");
       this.$store.dispatch('a/dec')
    },
  },

6.效果:

7.在创建一个变量B:

import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex)

let A = {
    namespaced: true,
    state: {
        count: 0
    }, //存值

    // 下面都是方法
    mutations: {
        increment(state, n) {
            state.count += n
        },
        decrement(state, n) {
            state.count -= n
        }
    },
    actions: {
        dec({ commit }) {
            commit("decrement", 10)
        },
        // add({ commit }) {
        //     commit("increment", 10)
        // },
        add(contxt) {
            contxt.commit("increment", 10)
        }
    },
    getters: {
        desc(state) {
            if (state.count < 50) {
                return "吃饭"
            } else if (state.count < 100) {
                return "睡觉"
            } else {
                return "打豆豆"
            }
        }
    }
}

let B = {
    namespaced: true,
    state: {
        count: 0
    }, //存值

    // 下面都是方法
    mutations: {
        increment(state, n) {
            state.count += n
        },
        decrement(state, n) {
            state.count -= n
        }
    },
    actions: {
        dec({ commit }) {
            commit("decrement", 10)
        },
        // add({ commit }) {
        //     commit("increment", 10)
        // },
        add(contxt) {
            contxt.commit("increment", 10)
        }
    },
    getters: {
        desc(state) {
            if (state.count < 50) {
                return "吃饭"
            } else if (state.count < 100) {
                return "睡觉"
            } else {
                return "打豆豆"
            }
        }
    }
}

export default new Vuex.Store({

    modules: {
        a: A,
        b: B
    },

})

 在home.vue:

<template>
  <div class="home">
    <h1>{{ $store.state.count }}</h1>
    <h2>{{$store.getters.desc}}</h2>
    <h3>{{$store.state.a.count}}</h3>
    <h3>{{$store.state.b.count}}</h3>
    <button @click="add">++</button>
    <button @click="decrement">--</button>
    <HelloWorld msg="Welcome to Your Vue.js App" />
  </div>
</template>

修改方法:

 methods: {
    add() {
      // this.$store.commit("increment",10);
      this.$store.dispatch("a/add");
      this.$store.dispatch("b/add");
    },
    decrement() {
      // this.$store.commit("decrement");
      this.$store.dispatch("a/dec");
      this.$store.dispatch("b/dec");
    },
  },

8.效果:

 七、标准项目结构

如果所有的状态都写在一个 js 中,这个 js 必定会很臃肿,Vuex 并不限制你的代码结构。但是它建议你按以下代码结构来构建项目结构:

1. 重构项目结构

1. 1在src下新建一个newStore文件夹, 在此文件夹下创建 index.js,actions.js,mutations.js和modules 目录,在该目录下创建 demo1.js 和demo2.js 

demo1.js:

let A = {
    namespaced: true,
    state: {
        count: 0
    }, //存值

    // 下面都是方法
    mutations: {
        increment(state, n) {
            state.count += n
        },
        decrement(state, n) {
            state.count -= n
        }
    },
    actions: AA,
    getters: {
        desc(state) {
            if (state.count < 50) {
                return "吃饭"
            } else if (state.count < 100) {
                return "睡觉"
            } else {
                return "打豆豆"
            }
        }
    }
}
export default A

demo2.js :

let B = {
    namespaced: true,
    state: {
        count: 0
    }, //存值

    // 下面都是方法
    mutations: {
        increment(state, n) {
            state.count += n
        },
        decrement(state, n) {
            state.count -= n
        }
    },
    actions: {
        dec({ commit }) {
            commit("decrement", 10)
        },
        // add({ commit }) {
        //     commit("increment", 10)
        // },
        add(contxt) {
            contxt.commit("increment", 10)
        }
    },
    getters: {
        desc(state) {
            if (state.count < 50) {
                return "吃饭"
            } else if (state.count < 100) {
                return "睡觉"
            } else {
                return "打豆豆"
            }
        }
    }
}
export default B

 newStore\index.js:

import Vue from 'vue'
import Vuex from 'vuex'

import A from './modules/demo1.js'
import B from './modules/demo2.js'

Vue.use(Vuex)

export default new Vuex.Store({

    modules: {
        a: A,
        b: B
    },

})

在main.js中把原来的注释上,导入新的store,也就是newStore:

import store from './newStore'

在actions.js中:

let AA = {
    dec({ commit }) {
        commit("decrement", 10)
    },
    add(contxt) {
        contxt.commit("increment", 10)
    }
}
export { AA }

2. 正常访问, 与重构前一样

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值