Vuex学习小结

1. 理解 Vuex

1.1 vuex是什么

专门在 Vue中实现集中式状态(数据)管理的一个 vue 插件,对 vue 应用中多个组件的共享状态进行集中式的管理(读/写),也是一种组件间的通讯方式,且适用于任意组件间的通讯。

多组件共享数据

1.2 什么情况下使用 vuex

  • 多个组件依赖于同一状态
  • 来自不同组件的行为需要变更同一状态

在这里插入图片描述

1.3 Vuex 工作原理

在这里插入图片描述

2. 安装及其使用

2.1安装和初始化工作

  • 下载 npm i vuex@2.3.1 --save

  • 使用插件 Vue.use(Vuex)

    new 实例对象时可以加入 store 的配置项

    // 引入 vuex
    import Vuex from 'vuex'
    // 使用插件
    Vue.use(Vuex)
    
  • 创建 store

在 src 目录下创建 store 文件夹,放一个 index.js 文件

src/store/index.js

// 该文件用于创建 Vuex 中最为核心的 store
// 引入 Vuex
import Vuex from 'vuex'
// 准备 actions 
// 用于响应组件的动作
const actions = {}
// 准备 mutations
// 用于操作数据
const mutations = {}
// 准备 state
// 用于储存数据
const state = {}
// 创建并导出 store
export default new Vuex.Store({
  actions,
  mutations,
  state
})

main.js 中引入 store并配置

import Vue from 'vue'
import App from './App.vue'
// 引入 vuex
import Vuex from 'vuex'
// 引入 store
import store from './store'
Vue.config.productionTip = false

// 使用插件
Vue.use(Vuex)

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

报错Uncaught Error: [vuex] must call Vue.use(Vuex) before creating a store instance.

Vue.use(Vuex) 需要在创建 store 之前执行

不能通过调整 import 语句的顺序来解决这个问题,因为vue脚手架会将import语句提升到文件最前面执行,解决:将 Vue.use(Vuex) 这行代码放在 src/store/index.js 的文件中靠前面的位置。

// 该文件用于创建 Vuex 中最为核心的 store
// 引入 Vuex
import Vuex from 'vuex'
import Vue from 'vue'

// 使用插件
Vue.use(Vuex)
//..code

2.2 使用

  • sum 放在 state

    const state = {
          // 当前的和
          sum: 0
    }
    
  • actions 中添加 add 方法

    • add 方法包含两个参数 context ,value
    • context mini版的 store,是一个上下文,包含commit,可以调用向 mutations提交处理
    • value 是传入的值
    • 最好将 actions中的方法名写成小写,将 mutations 中的方法名写成大写,便于区分
    const actions = {
      add(context,value){
        console.log('add',context,value)
        context.commit('add' , value)
      }
    }
    
  • mutations 中添加 ADD方法

    参数 state 中存放着数据,和一些方法

    const mutations = {
      ADD(state,value){
        console.log(state,value)
        state.sum += value
      }
    }
    
  • 在页面中使用插值语法展示state中的数据

    <h1>当前求和 : {{$store.state.sum}}</h1>
    
  • 完善 methods ,actions 和 mutations

    methods: {
        increment(){
          this.$store.dispatch('add' , this.n)
        },
        decrement(){
          this.$store.dispatch('sub' , this.n)
        },
        incrementOdd(){
            this.$store.dispatch('addOdd' , this.n)
        },
        incrementWait(){
            this.$store.dispatch('addWait' , this.n)
        }
      }
    
    const actions = {
      add(context,value){
        console.log('actions 调用了 add')
        context.commit('ADD' , value)
      },
      sub(context,value){
        console.log('actions 调用了 sub')
        context.commit('SUB' , value)
      },
      addOdd(context,value){
        console.log('actions 调用了 addOdd')
        if(context.state.sum %2 != 0){
          context.commit('ADD' , value)
        }
      },
      addWait(context,value){
        console.log('actions 调用了 addWait')
        setTimeout(() => {
          context.commit('ADD' , value)
        },3000)
      },
    }
    
    const mutations = {
      ADD(state,value){
        console.log('mutations 调用了 ADD')
        state.sum += value
      },
      SUB(context,value){
        console.log('mutations 调用了 SUB')
        state.sum -= value
      }
    }
    
  • 由于 actions 中只有一个 commit 逻辑,可以简化

    将 dispatch 改成 commit,并且将调用的小写的actions中的方法改成大写的 mutations中的方法

    increment(){
        this.$store.commit('ADD' , this.n)
    },
    decrement(){
       this.$store.commit('SUB' , this.n)
    },
    

3. Vuex 开发者工具

在这里插入图片描述

4. store 的一些配置项

4.1 getters

在 state 中的数据需要经过加工之后再使用,可以使用 getters 加工

组件中通过 $store.getters.xxx 访问

类似于计算属性,但是计算属性只能在当前组件中访问到

state ==> getters

data ==> computed

src/store/index.js 中追加 getters 配置:

// 准备 getters 用于将 state 中的数据加工
const getters = {
  bigSum(state){
    return state.sum * 10
  }
}

export default new Vuex.Store({
  // ...
  getters
})

4.2 mapState 和 mapGetters

  • mapState 帮助我们映射 state 中的数据为计算属性

  • mapGetters 帮助我们映射 getters 中的数据为计算属性

原始的组件页面结构,太臃肿

<h1>当前求和 : {{$store.state.sum}}</h1>
<h3>我在{{$store.state.school}},学习{{$store.state.subject}}</h3>
  • 在 script 中引入 vuex

    import {mapState} from 'vuex'
    
  • 在computed 中生成计算属性的代码

    computed:{
            // 借助 mapState 生成计算属性,从 state 中读取数据 (对象写法)
        ...mapState({
            sum: 'sum',
            school: 'school',
            subject: 'subject'
        }),
            // 数组写法
        ...mapState(['sum','school','subject']),
        //相当于 
        //sum(){
        //  return this.$store.state.sum
        //}
    },
    
  • 页面结构,更加简洁

    <h1>当前求和 : {{sum}}</h1>
    <h3>我在{{school}},学习{{subject}}</h3 														
    
  • mapGetters

    <h1> * 10 过后 : {{$store.getters.bigSum}}</h1>
    <h1> * 10 过后 : {{bigSum}}</h1>
    
    import {mapState , mapGetters} from 'vuex'
    
    // 借助 mapGetters 生成计算属性,从 getters 中读取数据 (对象写法)
        ...mapGetters({
          bigSum: 'bigSum',
        }),
        // 数组写法
        ...mapGetters(['bigSum']),
    

4.3 mapActions 与 mapMutations

  • 用于帮助我们生成与 mutations 对话的方法,包含 $store.commit(xxx)的函数

    • 原生手写的代码和使用 mapMutations

      // increment(){
      //   this.$store.commit('ADD' , this.n)
      // },
      // decrement(){
      //   this.$store.commit('SUB' , this.n)
      // },
      ...mapMutations({
          increment: 'ADD',
          decrement: 'SUB'
      }),
      
    • 注意:使用 mapMutations 时,相当于

      increment(e){ this.$store.commit('ADD' , e) }

      所以 n 需要我们在触发事件函数的时候手动传参

      <button @*click*="increment(n)">+</button>

  • 用于帮助我们生成与 mutations 对话的方法,包含 this.$store.dispatch(xxx)的函数

    ...mapActions({
        incrementOdd: 'addOdd',
        incrementWait: 'addWait'
    })
    

5. 多组件共享数据

添加一个 Person.vue 组件来实现与 Count.vue 组件通过 vuex 来共享

6. 模块化 + 命名空间

  1. 目的:让代码更好维护,让多种数据分类更多明确。

  2. 修改 store/index.js

    import countOptions from './count'
    import personOptions from './person'
    
    export default new Vuex.Store({
      modules: {
        countAbout: countOptions,
        personAbout: personOptions
      }
    })
    

    count.js

    // 求和相关配置
    const countOptions = {
      namespaced: true,//开启命名空间
      actions: {
        addOdd(context,value){
          console.log('actions 调用了 addOdd')
          if(context.state.sum %2 != 0){
            context.commit('ADD' , value)
          }
        },
        addWait(context,value){
          console.log('actions 调用了 addWait')
          setTimeout(() => {
            context.commit('ADD' , value)
          },3000)
        },
      },
      mutations: {
        ADD(state,value){
          console.log('mutations 调用了 ADD')
          state.sum += value
        },
        SUB(state,value){
          console.log('mutations 调用了 SUB')
          state.sum -= value
        },
      },
      state: {
        // 当前的和
          sum: 0,
          school: '尚硅谷',
          subject: '前端',
      },
      getters: {
        bigSum(state){
          return state.sum * 10
        }
      }
    }
    
    export default countOptions
    

    person.js

    // 人员相关配置
    import {nanoid} from 'nanoid'
    
    const personOptions = {
      namespaced: true,//开启命名空间   
      actions: {
        addPersonWang(context,value){
          if(value.name.indexOf('王') === 0){
            context.commit('ADD_PERSON', value)
          }else{
            alert('添加的人员姓必须是王!')
          }
        },
        addPersonServer(context){
          var ajax = new XMLHttpRequest()
          ajax.open('get','https://api.uixsj.cn/hitokoto/get?type=social')
          ajax.send()
          ajax.onreadystatechange = function () {
            if (ajax.readyState==4 &&ajax.status==200) {
              context.commit('ADD_PERSON', {
                id: nanoid(),
                name: ajax.responseText
              })
            }
          }
          // axios.get('https://api.uixsj.cn/hitokoto/get?type=social').then(
          //   response => {
          //     context.commit('ADD_PERSON', {
          //       id: nanoid(),
          //       name: response.data
          //     })
          //   },
          //   err => {
          //     alert(err.message)
          //   }
          // )
        }
      },
      mutations: {
        ADD_PERSON(state,value){
          console.log('mutations 调用了 ADD_PERSON')
          state.personList.unshift(value)
        }
      },
      state: {
        personList:[
            {id: '001', name: '张三'}
          ]
      },
      getters: {
        // state 是相对于当前的配置组件
        firstPersonName(state){
          return state.personList[0].name
        }
      }
    }
    
    export default personOptions
    
    
  3. 开启命名空间后,组件中读取 state 数据

    this.$store.state.personAbout.personList
    
    ...mapState('countAbout',['sum','school','subject']),
    
  4. 开启命名空间后,组件中读取 getters 数据

    this.$store.getters['personAbout/firstPersonName']
    
    ...mapGetters('countAbout',['bigSum']),
    
  5. 开启命名空间后,组件中调用 dispatch

    this.$store.dispatch('personAbout/addPersonWang', personObj)
    
    ...mapActions('countAbout',{
        incrementOdd: 'addOdd',
        incrementWait: 'addWait'
    })
    
  6. 开启命名空间后,组件中调用 commit

    this.$store.commit('personAbout/ADD_PERSON', personObj)
    
    ...mapMutations('countAbout',{
        increment: 'ADD',
        decrement: 'SUB'
    }),
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值