Vue基础入门(4)- Vuex的使用

Vue基础入门(4)- Vuex的使用

Vuex

主要内容:Store以及其中的state、mutations、actions、getters、modules属性

介绍 :Vuex 是一个 Vue 的 状态管理工具,状态就是数据

大白话:Vuex 是一个插件,可以帮我们管理 Vue 通用的数据 (多组件共享的数据)。例如:购物车数据 个人信息数据

使用场景:

  • 某个状态 在 很多个组件 来使用 (个人信息)

  • 多个组件 共同维护 一份数据 (购物车)

优势:

  • 共同维护一份数据,数据集中化管理

  • 响应式变化

  • 操作简洁 (vuex提供了一些辅助函数)

    注意:

    • 不是所有的场景都适用于vuex,只有在必要的时候才使用vuex
    • 使用了vuex之后,会附加更多的框架中的概念进来,增加了项目的复杂度 (数据的操作更便捷,数据的流动更清晰)

22.1 多组件共享数据

使用场景:

多个组件共享一份数据

任意一个组件都可以修改数据

22.2 创建仓库

安装:

安装vuex与vue-router类似,vuex是一个独立存在的插件,如果脚手架初始化没有选 vuex,就需要额外安装。

bash 复制代码
yarn add vuex@3 或者 npm i vuex@3

新建 store/index.js 专门存放 vuex:

创建仓库 store/index.js

js 复制代码
// 导入 vue
import Vue from 'vue'
// 导入 vuex
import Vuex from 'vuex'
// vuex也是vue的插件, 需要use一下, 进行插件的安装初始化
Vue.use(Vuex)

// 创建仓库 store
const store = new Vuex.Store({
    
    //后期会写大量配置
})

// 导出仓库
export default store

在 main.js 中导入挂载到 Vue 实例上:

  • 导入store
  • store为状态管理器,用于在 Vue 应用的各个组件之间共享状态
js 复制代码
import Vue from 'vue'
import App from './App.vue'
import store from './store'

Vue.config.productionTip = false

new Vue({
  render: h => h(App),
  store
}).$mount('#app')

此刻起, 就成功创建了一个 空仓库

22.3 state 状态 重要

明确如何给仓库 提供数据 ,如何 使用仓库的数据

  • State提供唯一的公共数据源,所有共享的数据都要统一放到Store中的State中存储

  • 打开项目中的store.js文件,在state对象中可以添加我们要共享的数据。

js 复制代码
// 创建仓库 store
const store = new Vuex.Store({
  // state 状态, 即数据, 类似于vue组件中的data,
  // 区别:
  // 1.data 是组件自己的数据, 
  // 2.state 中的数据整个vue项目的组件都能访问到
  state: {
    count: 101
  }
})

22.4 访问数据

  1. 通过store直接访问 → {{ store.state.count }}
  2. 通过辅助函数mapState 映射计算属性 ---> {{ count }}
22.4.1 通过$store访问的语法
js 复制代码
获取 store:
 1.Vue模板中获取 this.$store
 2.js文件中获取 import 导入 store


模板中:     {{ $store.state.xxx }}
组件逻辑中:  this.$store.state.xxx
JS模块中:   store.state.xxx

模板中:

vue 复制代码
<h1>state的数据 - {{ $store.state.count }}</h1>

逻辑中:

将state属性定义在计算属性中 https://vuex.vuejs.org/zh/guide/state.html

js 复制代码
<h1>state的数据 - {{ count }}</h1>

// 把state中数据,定义在组件内的计算属性中
  computed: {
    count () {
      return this.$store.state.count
    }
  }

js文件中:

js 复制代码
//main.js

import store from "@/store"

console.log(store.state.count)
22.4.2 通过辅助函数mapState 映射计算属性

mapState是辅助函数,帮助我们把store中的数据映射到 组件的计算属性中, 它属于一种方便的用法

用法:

导入:

在相关vue的逻辑代码中

js 复制代码
import { mapState } from 'vuex'

采用数组形式引入state属性:

js 复制代码
mapState(['count']) 

上面代码的最终得到的是 类似于

js 复制代码
count () {
    return this.$store.state.count
}

利用展开运算符 将导出的状态映射给计算属性:

展开运算符:js语法中的基础知识点。

js 复制代码
  computed: {
    ...mapState(['count'])
  }

上面的代码相当于:

js 复制代码
computed: {
 count () {
   return this.$store.state.count
 }
}

mapState映射一般都写在computed计算属性中

vue 复制代码
 <div> state的数据:{{ count }}</div>
22.4.3 开启严格模式及Vuex的单项数据流

明确 vuex 同样遵循单向数据流,组件中不能直接修改仓库的数据

开启严格模式

通过 strict: true 可以开启严格模式,开启严格模式后,直接修改state中的值会报错

state数据的修改只能通过mutations,并且mutations必须是同步的

22.5 核心概念-mutations

mutations是一个对象,对象中存放修改state的方法

22.5.1 定义mutations
js 复制代码
const store  = new Vuex.Store({
  state: {
    count: 0
  },
  // 定义mutations
  mutations: {
     
  }
})

格式说明:

mutations是一个对象,对象中存放修改state的方法

js 复制代码
mutations: {
    // 方法里参数 第一个参数是当前store的state属性
    // payload 载荷 运输参数 调用mutations的时候 可以传递参数 传递载荷
    addCount (state) {
      state.count += 1
    }
  },

组件中提交 mutations:

js 复制代码
this.$store.commit('addCount')
22.5.2 带参数的 mutations

提交 mutation 是可以传递参数的 this.$store.commit('xxx', 参数)

提供mutation函数(带参数):

js 复制代码
mutations: {
  ...
  addCount (state, count) {
    state.count = count
  }
},

提交mutation:

js 复制代码
handle ( ) {
  this.$store.commit('addCount', 10)
}

小tips: 提交的参数只能是一个, 如果有多个参数要传, 可以传递一个对象:

js 复制代码
this.$store.commit('addCount', {
  count: 10
})

第二部分和第三部分的代码写在哪里呢?

相关vue模块的逻辑代码中

22.6 Vuex中的值和组件中的input双向绑定

熟练mutations 传参语法,实时输入,实时更新。

但注意,数据只能单向传播,如下图,只能通过根组件,去修改子组件中的数

22.6.1 实现步骤

1~2步:

App.vue

vue 复制代码
<input :value="count" @input="handleInput" type="text">

第 3 步:

store/index.js

js 复制代码
mutations: { 
   changeCount (state, newCount) {
      state.count = newCount
   }
},

第 4 步:

App.vue

vue 复制代码
<input :value="count" @input="handleInput" type="text">

export default {
  methods: {
    handleInput (e) {
      // 1. 实时获取输入框的值
      const num = +e.target.value
      // 2. 提交mutation,调用mutation函数
      this.$store.commit('changeCount', num)
    }
  }
}

22.7 辅助函数- mapMutations

mapMutations和mapState很像,它把位于mutations中的方法提取了出来,我们可以将它导入

前面我们用mapState可以获取Store中的state数据

js 复制代码
import  { mapMutations } from 'vuex'
methods: {
    ...mapMutations(['addCount'])
}

上面代码的含义是将mutations的方法导入了methods中,等价于

js 复制代码
methods: {
      // commit(方法名, 载荷参数)
      addCount () {
          this.$store.commit('addCount')
      }
 }

此时,就可以直接通过this.addCount调用了

jsx 复制代码
<button @click="addCount">值+1</button>

但是请注意: Vuex中mutations中要求不能写异步代码,如果有异步的ajax请求,应该放置在actions中(下面一节内容)

与mapState对比:

mapState是返回state值,获取值;mapMutations是调用mutation中的方法

22.8 核心概念 - actions

state是存放数据的,mutations是同步更新数据 (便于监测数据的变化, 更新视图等, 方便于调试工具查看变化),

actions则负责进行异步操作

说明:mutations必须是同步的

需求: 一秒钟之后, 要给一个数去修改state

定义actions

js 复制代码
mutations: {
  changeCount (state, newCount) {
    state.count = newCount
  }
}


actions: {
  setAsyncCount (context, num) {
    // 一秒后, 给一个数, 去修改 num
    setTimeout(() => {
      context.commit('changeCount', num)
    }, 1000)
  }
},

组件中通过dispatch调用

js 复制代码
setAsyncCount () {
  this.$store.dispatch('setAsyncCount', 666)
}
  1. actions中的方法,异步调用mutations中的方法;
  2. mutations中的方法,修改state中的数据

22.9 辅助函数 -mapActions

mapActions 是把位于 actions中的方法提取了出来,映射到组件methods中

Son2.vue

js 复制代码
import { mapActions } from 'vuex'
methods: {
   ...mapActions(['changeCountAction'])
}

//mapActions映射的代码 本质上是以下代码的写法
//methods: {
//  changeCountAction (n) {
//    this.$store.dispatch('changeCountAction', n)
//  },
//}

直接通过 this.方法 就可以调用

vue 复制代码
<button @click="changeCountAction(200)">+异步</button>

间接实现在methods中调用actions中的异步方法

22.10 核心概念 - getters

除了state之外,有时我们还需要从state中**筛选出符合条件的一些数据**,这些数据是依赖state的,此时会用到getters

例如,state中定义了list,为1-10的数组,

js 复制代码
state: {
    list: [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
}

组件中,需要显示所有大于5的数据,正常的方式,是需要list在组件中进行再一步的处理,但是getters可以帮助我们实现它

定义getters

js 复制代码
getters: {
// getters函数的第一个参数是 state
// 必须要有返回值
 filterList:  state =>  state.list.filter(item => item > 5)
}

使用getters

  1. 原始方式-$store

    vue 复制代码
    <div>{{ $store.getters.filterList }}</div>
  2. 辅助函数 - mapGetters

    复制代码
    computed: {
        ...mapGetters(['filterList'])
    }
    vue 复制代码
    <div>{{ filterList }}</div>

使用小结

22.11 核心概念 - module

由于使用单一状态树 ,应用的所有状态会集中到一个比较大的对象。当应用变得非常复杂时,store 对象就有可能变得相当臃肿。

这句话的意思是,如果把所有的状态都放在state中,当项目变得越来越大的时候,Vuex会变得越来越难以维护

由此,又有了Vuex的模块化

22.11.1 模块定义

定义两个模块 usersetting

store下建立modules文件

user中管理用户的信息状态 userInfo modules/user.js

js 复制代码
const state = {
  userInfo: {
    name: 'zs',
    age: 18
  }
}

const mutations = {}

const actions = {}

const getters = {}

export default {
  state,
  mutations,
  actions,
  getters
}

setting中管理项目应用的 主题色 theme,描述 desc, modules/setting.js

js 复制代码
const state = {
  theme: 'dark'
  desc: '描述真呀真不错'
}

const mutations = {}

const actions = {}

const getters = {}

export default {
  state,
  mutations,
  actions,
  getters
}

store/index.js文件中的modules配置项中,注册这两个模块:

js 复制代码
import user from './modules/user'
import setting from './modules/setting'

const store = new Vuex.Store({
    modules:{
        user,
        setting
    }
})

使用模块中的数据, 可以直接通过模块名访问 $store.state.模块名.xxx => $store.state.setting.desc

也可以通过 mapState 映射

22.11.2 获取模块内的state数据

尽管已经分模块了,但其实子模块的状态,还是会挂到根级别的 state 中,属性名就是模块名

使用模块中的数据:

  1. 直接通过模块名访问 $store.state.模块名.xxx
  2. 通过 mapState 映射:
    1. 默认根级别的映射 mapState([ 'xxx' ])
    2. 子模块的映射 :mapState('模块名', ['xxx']) - 需要开启命名空间 namespaced:true

代码示例:

modules/user.js(开启了命名空间)

js 复制代码
const state = {
  userInfo: {
    name: 'zs',
    age: 18
  },
  myMsg: '我的数据'
}

const mutations = {
  updateMsg (state, msg) {
    state.myMsg = msg
  }
}

const actions = {}

const getters = {}

export default {
  namespaced: true,
  state,
  mutations,
  actions,
  getters
}

$store直接访问

html 复制代码
<!-- 测试访问模块中的state - 原生 -->
<div>{{ $store.state.user.userInfo.name }}</div>

mapState辅助函数访问(写在相关模块逻辑代码的computed属性中)

js 复制代码
...mapState('user', ['userInfo']),
...mapState('setting', ['theme', 'desc']),
22.11.3 获取模块内的getters数据

回顾:getters是state中筛选出来的一些数据

语法:

使用模块中 getters 中的数据:

  1. 直接通过模块名访问 $store.getters['模块名/xxx ']
  2. 通过 mapGetters 映射
    1. 默认根级别的映射 mapGetters([ 'xxx' ])
    2. 子模块的映射 mapGetters('模块名', ['xxx']) - 需要开启命名空间

代码演示:

modules/user.js

js 复制代码
const getters = {
  // 分模块后,state指代子模块的state
  UpperCaseName (state) {
    return state.userInfo.name.toUpperCase()
  }
}

Son1.vue 直接访问getters

html 复制代码
<!-- 测试访问模块中的getters - 原生 -->
<div>{{ $store.getters['user/UpperCaseName'] }}</div>

Son2.vue 通过命名空间访问

js 复制代码
computed:{
  ...mapGetters('user', ['UpperCaseName'])
}
22.11.4 获取模块内的mutations方法

回顾:mutations是一个对象,对象中存放修改state的方法

注意:默认模块中的 mutation 和 actions 会被挂载到全局,需要开启命名空间,才会挂载到子模块。

调用方式:

  1. 直接通过 store 调用 $store.commit('模块名/xxx ', 额外参数)
  2. 通过 mapMutations 映射
    1. 默认根级别的映射 mapMutations([ 'xxx' ])
    2. 子模块的映射 mapMutations('模块名', ['xxx']) - 需要开启命名空间

代码实现:

modules/user.js

js 复制代码
const mutations = {
  setUser (state, newUserInfo) {
    state.userInfo = newUserInfo
  }
}

modules/setting.js

js 复制代码
const mutations = {
  setTheme (state, newTheme) {
    state.theme = newTheme
  }
}

Son1.vue

vue 复制代码
<button @click="updateUser">更新个人信息</button> 
<button @click="updateTheme">更新主题色</button>


export default {
  methods: {
    updateUser () {
      // $store.commit('模块名/mutation名', 额外传参)
      this.$store.commit('user/setUser', {
        name: 'xiaowang',
        age: 25
      })
    }, 
    updateTheme () {
      this.$store.commit('setting/setTheme', 'pink')
    }
  }
}

Son2.vue

vue 复制代码
<button @click="setUser({ name: 'xiaoli', age: 80 })">更新个人信息</button>
<button @click="setTheme('skyblue')">更新主题</button>

methods:{
// 分模块的映射
...mapMutations('setting', ['setTheme']),
...mapMutations('user', ['setUser']),
}
22.11.5 获取模块内的actions方法

**注意:**默认模块中的 mutation 和 actions 会被挂载到全局,需要开启命名空间,才会挂载到子模块。

调用语法:

  1. 直接通过 store 调用 $store.dispatch('模块名/xxx ', 额外参数)
  2. 通过 mapActions 映射
    1. 默认根级别的映射 mapActions([ 'xxx' ])
    2. 子模块的映射 mapActions('模块名', ['xxx']) - 需要开启命名空间

代码实现:

modules/user.js

js 复制代码
const actions = {
  setUserSecond (context, newUserInfo) {
    // 将异步在action中进行封装
    setTimeout(() => {
      // 调用mutation   context上下文,默认提交的就是自己模块的action和mutation
      context.commit('setUser', newUserInfo)
    }, 1000)
  }
}

Son1.vue 直接通过store调用

vue 复制代码
<button @click="updateUser2">一秒后更新信息</button>

methods:{
    updateUser2 () {
      // 调用action dispatch
      this.$store.dispatch('user/setUserSecond', {
        name: 'xiaohong',
        age: 28
      })
    },
}

Son2.vue mapActions映射

vue 复制代码
<button @click="setUserSecond({ name: 'xiaoli', age: 80 })">一秒后更新信息</button>

methods:{
  ...mapActions('user', ['setUserSecond'])
}
Vuex模块化的使用小结
1.直接使用
  1. state --> $store.state.模块名.数据项名
  2. getters --> $store.getters['模块名/属性名']
  3. mutations --> $store.commit('模块名/方法名', 其他参数)
  4. actions --> $store.dispatch('模块名/方法名', 其他参数)
2.借助辅助方法使用

1.import { mapXxxx, mapXxx } from 'vuex'

computed、methods: {

​ // ...mapState、...mapGetters放computed中;

​ // ...mapMutations、...mapActions放methods中;

​ ...mapXxxx('模块名', ['数据项|方法']),

​ ...mapXxxx('模块名', { 新的名字: 原来的名字 }),

}

2.组件中直接使用 属性 {``{ age }} 或 方法 @click="updateAge(2)"

相关推荐
侠客行03174 小时前
Mybatis连接池实现及池化模式
java·mybatis·源码阅读
蛇皮划水怪4 小时前
深入浅出LangChain4J
java·langchain·llm
子兮曰4 小时前
OpenClaw入门:从零开始搭建你的私有化AI助手
前端·架构·github
吴仰晖4 小时前
使用github copliot chat的源码学习之Chromium Compositor
前端
1024小神4 小时前
github发布pages的几种状态记录
前端
老毛肚5 小时前
MyBatis体系结构与工作原理 上篇
java·mybatis
风流倜傥唐伯虎6 小时前
Spring Boot Jar包生产级启停脚本
java·运维·spring boot
不像程序员的程序媛6 小时前
Nginx日志切分
服务器·前端·nginx
Yvonne爱编码6 小时前
JAVA数据结构 DAY6-栈和队列
java·开发语言·数据结构·python
Re.不晚6 小时前
JAVA进阶之路——无奖问答挑战1
java·开发语言