Vuex 深入浅出超详细

Vuex 深入浅出超详细

什么是Vuex🤔❓

Vuex 官网🔗: Vuex 是一个专为 Vue.js 应用程序设计的状态管理库,它提供了一种集中式管理 应用中的状态;

状态管理模式: 它让组件的状态(数据),管理变得集中、有序,便于在整个应用中,共享和维护数据;

集中式存储: 它将应用的所有组件状态(数据),集中到一个单一的存储对象中,使得统一管理;


这是什么意思呢🤔❓

在复杂的Vue应用中: 多个组件常常需要共享状态(数据),直接传递props、使用事件机制会使程序变得 复杂且难以维护;

Vuex 是一个插件,可以帮我们管理 vue 通用的数据实现:多组件数据共享,多组件共同修改数据信息;

Vuex 应用场景: 跨组件共享状态 比如用户信息、购物车内容等,Vuex 提供了一个中心化的存储,

使得这些数据可以在任何组件中访问和更新,而无需通过复杂的父子组件传递或事件监听;

(官方)注意: 不是所有的场景都适用于Vuex,只有在必要的时候才使用Vuex

使用了Vuex之后,会附加更多的框架中的概念进来,增加了项目的复杂度,(数据的操作更便捷,数据的流动更清晰)

创建\使用:Vuex

自定义创建项目:

vue create vuex-demo 勾选:css预处理器、正常情况还需要勾选 vuexrouter 此处演示个人搭建环境;

安装Vuex 创建仓库:

vuex是一个独立存在的插件,如果脚手架初始化没有选 vuex,就需要额外安装,注意版本兼容:vue2\3\3原则;

sh 复制代码
yarn add vuex@3		#或 	npm i vuex@3

创建仓库 store/index.js

为了维护项目目录的整洁,在src目录下新建一个store目录其下放置一个index.js📄

Vuex的store是一个集中存储应用所有组件共享状态的地方,所有,共享的数据都要统一放到 Store 中的 State 中存储;

它类似于一个全局数据仓库,在组件中访问状态: 通过this.$store访问store中的数据、触发mutations、调用actions

js 复制代码
// 导入 vue、vuex
import Vue from 'vue'
import Vuex from 'vuex'
// 启用 Vuex 插件
Vue.use(Vuex)

// 创建仓库 store 状态,即数据:  
// 类似于vue组件中的data、data 是组件自己的数据;
// state 中的数据整个vue项目的组件都能访问到;
const store = new Vuex.Store({
    state: {
        count: 100
    }
})
// 导出仓库 store
export default store

导入main 挂载Vue实例

在Vue应用中引入Storemain.js中导入store,并将其添加到Vue实例中作为选项;

js 复制代码
import Vue from 'vue'
import App from './App.vue'
import store from './store'
Vue.config.productionTip = false

new Vue({
  //挂载至Vue实例
  render: h => h(App),
  store
}).$mount('#app')

在组件中访问状态数据

App.js: 通过this.$store访问store中的数据,此数据可以在任何组件中进行访问;

html 复制代码
<template>
  <div id="app">
    <p>store公共仓库获取数据: {{  $store.state.count  }}</p>
  </div>
</template>
<script>
  export default { name: 'App', }
</script>
<style></style>

state状态:

在Vuex中,State是状态管理的核心组成部分之一,它扮演着应用单一数据源的角色:

单一数据源: StateVuex store中存储的所有组件共享的数据状态,官方定义: 将数据称为 State状态;

它提供了一个全局的、集中式的存储空间,使得任何组件都能访问到这些状态,从而实现状态的统一管理;

响应式 :Vue的响应式系统使得当state中的数据发生变化时,所有依赖于这些数据的Vue组件能够自动更新;

这意味着你可以在组件中直接使用store中的状态,并且当状态改变时,视图会自动响应这些变化;

多组件使用Vuex:

案例:App.JS 主组件中引入,多个组件同时获取:Vuex 的数据进行展示; Son1.vue\Son2.vue

html 复制代码
<template>
    <div class="box">
        <h2>Son1 子组件</h2>
        从vuex中获取的值: <label>{{  $store.state.count  }}</label>
    </div>
</template>
<script></script>
<style></style>

获取Vuex数据: 通过$store访问的语法,可以直接在组件组件脚本.JSsrc/main.JS 快速访问;

js 复制代码
//Vue模板中直接使用
{{ $store.state.xxx }}
//Vue模板.js文件中获取
this.$store.state.xxx
//src/main.JS 主文件中获取
import store from './store'
store.state.xxx;

辅助函数 mapState

mapState辅助函数 :为了简化组件中对state的访问,

Vuex提供了mapState辅助函数,可以将store中的状态映射为组件的计算属性;

正常情况下,我们在组件中访问数据通过: {{ $store.state.xxx }}this.$store.state.xxx...

实际使用过程有点麻烦,mapState函数,可以直接将 state-store状态数据 映射为一个计算属性直接访问: {{ xxx }}

  • mapState函数: mapState(['xxx','xxx']); 可以获取对应 store状态数据,赋值给 计算属性,方便快速访问;
html 复制代码
<template>
  <div id="app">
    <h1>
      根组件
      - {{ title }}
      <!-- - {{ $store.state.title }} -->
    </h1>
    <p>store公共仓库获取数据: {{ count }}</p> <!-- {{  $store.state.count  }} -->
    <hr>
    <Son1></Son1>
    <Son2></Son2>
  </div>
</template>
<script>
  import Son1 from './components/Son1.vue';
  import Son2 from './components/Son2.vue';
  import { mapState } from 'vuex';          //通过ES6 语法对象解构直接获取mapState;
  export default { 
    name: 'App',
    components: { Son1, Son2, },
    created(){
      //created初始化钩子函数\查看$store\mapState对象属性;
      console.log("组件脚本中访问Vuex: "+this.$store.state.title);
      console.log("mapState['title']: "+mapState(['title']));
      console.log("mapState 对象属性: "+mapState);
    },
    //计算属性
    computed:{
      ...mapState(['title','count']),       //通过ES6 语法对象展开运算符,导出的状态映射给计算属性;
      //如果没有 ...mapState(['title','count']), 为了方便页面获取 $store.state 状态数据,通常需要自定义函数;
      diytitle(){ return this.$store.state.title; } //方便组件使用,$store.state 状态数据,当然计算函数支持更多自定义操作;
    }
   }
</script>
<style></style>

使用State的注意事项

禁止直接修改:

直接修改store中的state状态数据是被严格禁止的,

任何状态的改变都必须通过提交mutation来完成,以确保状态变更的可追踪性和一致性;

模块化状态: 在大型应用中,状态可能会非常复杂,因此可以将state分割到不同的模块中,

每个模块拥有自己的state,这有助于管理复杂的状态结构,后面介绍:Vuex模块化

状态修改mutations

在Vuex中,mutations是用于改变状态唯一合法方式,它遵循严格同步规则,确保状态变更的可预测性和调试的便利性

Vuex 遵循单向数据流,组件中不能直接修改仓库的数据: 但, 默认情况下并不会报错; 👇👇

html 复制代码
<!-- Vuex store、state状态数据可以直接修改 -->
<template>
    <div class="box">
        <h2>Son1 子组件</h2>
        从vuex中获取的值: <label>{{  $store.state.count  }}</label>
        <button @click="$store.state.count++">值 + 1</button>  <!-- 错误写法但不会报错; -->
        <button @click="addcount2()">值 + 2</button>  <!-- 错误写法但不会报错; -->
    </div>
</template>
<script>
    export default { 
        //直接修改Vuex store、state状态数据
        methods:{ addcount2(){ this.$store.state.count+=2; } }
    }
</script>

Vuex 严格模式:

Vuex 的严格模式是一种开发时的辅助工具,它强制所有的状态变更必须通过 mutation 来进行:

这有助于维护状态的一致性,避免了状态的隐式修改,使得应用的行为更加可预测;

启用方式 :在创建 Vuex store 实例时,通过设置 strict: true 启用严格模式:

js 复制代码
const store = new Vuex.Store({
	strict: true
 	// ...store配置
});

mutatios 修改状态:

为什么可以直接修改,还要使用mutations:

Mutations是Vuex中实现状态变更的核心机制,它确保了状态的改变是有序的、可追踪的,并且遵循一定的规范:

  • 单一职责 :将状态变更逻辑封装在mutations中,使得这部分代码更加模块化和易于测试;

  • 可追踪性:通过集中管理状态变更,使得开发者可以更容易地跟踪应用状态的变化历史;

    特别是在使用Vue DevTools时,可以清晰地看到每次mutation对状态的影响;

使用:mutatios 修改state状态:

  • 在Vuex实例mutatios中定义=>处理函数: 这些函数必须是同步的,以确保状态变更的清晰和可追踪;

    每一个处理函数对应一个状态数据,它接收两个参数:state(必须、状态数据)payload(可选、传递参数)

  • 在需要操作state状态数据,调用对应mutation处理并提交: this.$store.commit('处理函数名', 传递参数);

定义 mutations 事件函数

在Vuex的store配置中,定义mutations对象,其中: 键 =是=>事件类型(通常是大写命名)值=是=>处理函数

js 复制代码
// 创建仓库 store 状态,即数据: 
// 类似于vue组件中的data、data 是组件自己的数据;
// state 中的数据整个vue项目的组件都能访问到;
const store = new Vuex.Store({
    //开启严格模式
    strict: true,
    state: {
        count: 10,
        title: "大标题1",
    },
    //mutations对象其中键是事件类型通常是大写命名)、值是处理函数;
    mutations:{
        //state: 表示当前Vuex中的state状态数据库,用来获取其操作数据;
        ADD_COUNT(state){ state.count++; },
        //带参传递数据: 参数只能一个,如果有多个参数,包装成一个{对象}\[数组] 传递;        
        ADD_COUNTX(state,payload){ state.count+=payload }
    }
})

使用 mutations 事件函数

在组件中通过,调用、提交:mutation处理函数,形式完成,状态修改: Son2.vue

html 复制代码
<template>
    <div class="box">
        <h2>Son2 子组件</h2>
        从vuex中获取的值: <label>{{  $store.state.count  }}</label>
        <button @click="addCount()">值 + 1</button>  <!-- mutatios修改state -->
        <button @click="addCountx(3)">值 + 3</button>  <!-- mutatios带 参? 修改state -->
        <button @click="addCountx(5)">值 + 5</button>  <!-- mutatios带 参? 修改state -->
    </div>
</template>
<script>
    export default {
        methods:{
            //无参自动+1
            addCount(){ this.$store.commit('ADD_COUNT'); },
            addCountx(x){ this.$store.commit('ADD_COUNTX',x); }     //自定义传参添加数值;
        }
    }
</script>

mapMutations-辅助函数

mapMutationsVuex提供的一个辅助函数,它简化了在Vue组件中提交mutation的过程:

这个辅助函数允许:store中的mutations映射到组件的methods中,

使得你可以直接在组件的方法中调用这些mutation

而不需要手动使用this.$store.commit

mapMutations 使用:

Son3.vue:mapState 用法类型,mapState 针对状态数据\使用计算属性进行优化,

mapMutations 针对状态数据修改操作\使用method 函数进行优化,自动将事件函数名,匹配生成一个method函数

html 复制代码
<template>
    <div class="box">
        <h2>Son3 子组件</h2>
        从vuex中获取的值: <label>{{  $store.state.count  }}</label>
        <button @click="addCount()">值 + 1</button>  <!-- mutatios修改state -->
        <button @click="addCountx(10)">值 + 10</button>  <!-- mutatios带 参? 修改state -->
        <button @click="ADD_COUNTX(-10)">值 - 10</button>  <!-- mutatios带 参? 修改state -->
    </div>
</template>
<script>
    import { mapMutations } from 'vuex';          //通过ES6 语法对象解构直接获取mapMutations;
    export default {
        methods:{
            //方式一: 直接映射名为increment的mutation
            ...mapMutations(['ADD_COUNT','ADD_COUNTX']),
            //方式二: 使用对象形式来映射并重命名
            ...mapMutations({
                'addCount' : "ADD_COUNT",      //组件方法名: store中的mutation名
                'addCountx' : "ADD_COUNTX",
            }),
        }
    }
</script>

注意: Vuex中mutations中不能写异步代码,如果有异步的ajax请求,应该放置在actions中;

异步操作action

在Vuex中,actions和mutations类似,是用于处理异步操作的关键部分:

它们允许你执行异步逻辑,比如API调用,并且最终通过触发一个或多个mutations来改变状态;

定义 actions 异步操作:

在Vuex的store配置中,定义actions对象: 虽然actions可以执行异步逻辑,但它们不能直接修改state

相反,它们通过调用context.commit来触发mutation,从而间接改变状态,也就是说:actions依赖mutation操作state;

js 复制代码
// 创建仓库 store 状态,即数据: 
// 类似于vue组件中的data、data 是组件自己的数据;
// state 中的数据整个vue项目的组件都能访问到;
const store = new Vuex.Store({
    //开启严格模式
    strict: true,
    state: {
        count: 10,
        title: "大标题1",
    },
    //mutations对象其中键是事件类型通常是大写命名)、值是处理函数;
    mutations:{
        //state: 表示当前Vuex中的state状态数据库,用来获取其操作数据;
        ADD_COUNT(state){ state.count++; },
        //带参传递数据: 参数只能一个,如果有多个参数,包装成一个{对象}\[数组] 传递;        
        ADD_COUNTX(state,payload){ state.count+=payload }
    },
    //actions 处理异步: 注意,不能直接操作state 操作state 还是需要context.commit('mutation名','传参');
    actions:{
        //actions 接收参数: context对象提供了对store的访问、payload作为参数对象
        changeCountAction(context,num){ 
            // 这里是setTimeout模拟异步,以后大部分场景是发请求
            setTimeout(() => { context.commit('ADD_COUNTX', num) }, 1000) 
        }
    }
})

使用 actions 异步操作:

在Vue组件中,你可以通过this.$store.dispatch('actions名','参数对象')来触发action

html 复制代码
<template>
    <div class="box">
        <h2>Son3 子组件</h2>
        从vuex中获取的值: <label>{{  $store.state.count  }}</label>
        <button @click="addCount()">值 + 1</button>  <!-- mutatios修改state -->
        <button @click="addCountx(10)">值 + 10</button>  <!-- mutatios带 参? 修改state -->
        <button @click="ADD_COUNTX(-10)">值 - 10</button>  <!-- mutatios带 参? 修改state -->
        <button @click="changeCountAction(888)">1秒后改成888</button>   <!-- actions 异步操作state -->
    </div>
</template>
<script>
    import { mapMutations } from 'vuex';          //通过ES6 语法对象解构直接获取mapMutations;
    export default {
        methods:{
            //方式一: 直接映射名为increment的mutation
            //方式二: 使用对象形式来映射并重命名 	....省略....
            //在Vue组件中,你可以通过this.$store.dispatch来触发action:
            async changeCountAction(x){
                await this.$store.dispatch('changeCountAction',x);
            },
        }
    }
</script>

mapaction-辅助函数

mapActions是Vuex提供的一个辅助函数,和mapMutations 类似,

它允许你将store中的actions便捷地映射到Vue组件的methods中,从而简化组件内调用这些异步操作的流程;

js 复制代码
//通过ES6 语法对象解构直接获取mapMutations...
import { mapMutations,mapActions } from 'vuex';   
export default {
    methods:{
        //mapActions 使用: 和mapMutations类似
        ...mapActions(['changeCountAction']),
        ...mapActions({
            "divChangeCountAction": "changeCountAction"
        }),
    }
}

getters 类计算属性:

Vuex 中的 getters 是用来从 store 的状态state中派生出一些状态的计算属性: 类似于组件中的 computed 计算属性;

  • 计算和过滤: getters 用于对 state 进行计算和过滤,生成新的数据视图;

    有时我们还需要从state中派生出一些状态,这些状态是依赖state的,此时会用到getters

  • 缓存机制: getters 的值会被缓存,只有当其依赖的 state 或其他 getters 发生变化时,才会重新计算;

  • 访问便捷: getters 可以通过 store.getters 访问,或者在 Vue 组件中通过 this.$store.getters 访问;

    这使得多个组件可以共享这些计算后的数据,避免代码重复

getters 案例Demo

例如: state中定义了list的数组,组件中,需要显示所有大于>5的数;

js 复制代码
// 创建仓库 store 状态,即数据: 
// 类似于vue组件中的data、data 是组件自己的数据;
// state 中的数据整个vue项目的组件都能访问到;
const store = new Vuex.Store({
    //开启严格模式
    strict: true,
    state: {
        count: 10,
        title: "大标题1",
        list: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
    },
    //getters 类似于计算属性,用来从 store.state 状态数据中派生出一些状态的计算属性;
    getters:{
        // state中定义了list的数组,需要显示所有大于>5的数;
        // 必须有返回值,返回值就是getters的值
        // 形参第一个参数,就是state
        filterList (state) { return state.list.filter(item => item > 5) }
    }
})

Son3组件中获取:getters数据: 通过 this.$store.getters 访问定义的 getters

html 复制代码
<template>
    <div class="box">
        <h2>Son3 子组件</h2>
        从vuex中获取的值: <label>{{  $store.state.count  }}</label>
        <div>getters过滤数据 {{ $store.getters.filterList }}</div>
    </div>
</template>

mapgetters-辅助函数

mapGetters 提供了一种高效、简洁的方式来访问 Vuex 中的 getters

减少了代码冗余,增强了组件的可读性和可维护性,是 Vue 应用中状态管理的重要工具之一

html 复制代码
<template>
    <div class="box">
        <h2>Son3 子组件</h2>
        从vuex中获取的值: <label>{{  $store.state.count  }}</label>
        <div>getters过滤数据 {{ $store.getters.filterList }}</div>
        <div>mapGetters便携获取数据 {{ filterList }}</div>
    </div>
</template>
<script>
    //通过ES6 语法对象解构直接获取mapMutations...
    import { mapMutations,mapActions,mapGetters } from 'vuex';  
    export default {
        computed:{ ...mapGetters(['filterList']), },		//组件计算函数		
    }
</script>
相关推荐
沉默璇年8 分钟前
react中useMemo的使用场景
前端·react.js·前端框架
yqcoder14 分钟前
reactflow 中 useNodesState 模块作用
开发语言·前端·javascript
2401_8827275723 分钟前
BY组态-低代码web可视化组件
前端·后端·物联网·低代码·数学建模·前端框架
会发光的猪。1 小时前
css使用弹性盒,让每个子元素平均等分父元素的4/1大小
前端·javascript·vue.js
天下代码客1 小时前
【vue】vue中.sync修饰符如何使用--详细代码对比
前端·javascript·vue.js
猫爪笔记1 小时前
前端:HTML (学习笔记)【1】
前端·笔记·学习·html
前端李易安2 小时前
Webpack 热更新(HMR)详解:原理与实现
前端·webpack·node.js
红绿鲤鱼2 小时前
React-自定义Hook与逻辑共享
前端·react.js·前端框架
周全全2 小时前
Spring Boot + Vue 基于 RSA 的用户身份认证加密机制实现
java·vue.js·spring boot·安全·php
Domain-zhuo2 小时前
什么是JavaScript原型链?
开发语言·前端·javascript·jvm·ecmascript·原型模式