Vuex 核心概念解释(State、Getters、Mutations、Actions、Modules)和简单案例

—— Vuex 的使用 ——

直接用途:多个组件共享状态

Vuex 官网:Vuex 是什么? | Vuex (vuejs.org)

1. state - 单一状态树

  • 官方解释

    State | Vuex (vuejs.org)

    Vuex 通过 Vue 的插件系统将 store 实例从根组件中“注入”到所有的子组件里。且子组件能通过 this.$store 访问到。

    类似 data属性

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

Vue.use(Vuex)

// 创建一个 store
const store = new Vuex.Store({
    // 1. 这样就给store里添加了一个 address 对象  这里写死了	以后用是外界传入的
    state: {
        address: {
            provinceName:"陕西省",
            cityName:"西安市",
            detailInfo:"xxx"
	   }
    }
})

export default store

2. Getters - 计算属性

Getter | Vuex (vuejs.org)

  • 官方解释

    有时候我们需要从 store 中的 state 中派生出一些状态,例如对列表进行过滤计数,这里我们计算完整的地址

    Vuex 允许我们在 store 中定义“getter”(可以认为是 store 的计算属性)。

    类似computed属性

  getters:{
    // 这里就动态计算了详细地址  '陕西省西安市xxx'
    addstr(state) {    
      return state.address.provinceName + state.address.cityName + state.address.countyName + state.address.detailInfo
    } 
  }

3. Mutations - 同步提交

  • 官方解释

Mutation | Vuex (vuejs.org)

​ 更改 Vuex 的 store 中的状态的唯一方法是提交 mutation。Vuex 中的 mutation 非常类似于事件:每个 mutation 都有一个字符串的事件类型 (type)**和一个**回调函数 (handler)。这个回调函数就是我们实际进行状态更改的地方,并且它会接受 state 作为第一个参数

  • 提交载荷(Payload)

    你可以向 store.commit 传入额外的参数 即 mutation 的载荷(payload)

    在大多数情况下,载荷应该是一个对象,这样可以包含多个字段并且记录的 mutation 会更易读

    这里address就是载荷

  mutations:{
    // 更新收货地址  外界传入一个 地址对象 更新当前 state 中的对象
    updateAddress(state, address){
      state.address = address
      // 多个方法下 这样调用  
      this.commit('saveAddressToStroage')
    },
    
    saveAddressToStroage(state){
      uni.setStorageSync('address',JSON.stringify(state.address))
    }
  }

​ 诶,有人就要问了,我写的异步提交方法怎么不生效啊?这里我们需要使用action

  • 使用常量替代 Mutation 事件类型

Mutation | Vuex (vuejs.org)

使用常量替代 mutation 事件类型在各种 Flux 实现中是很常见的模式。这样可以使 linter 之类的工具发挥作用,同时把这些常量放在单独的文件中可以让你的代码合作者对整个 app 包含的 mutation 一目了然:

// mutation-types.js
export const SOME_MUTATION = 'SOME_MUTATION'
// store.js
import { createStore } from 'vuex'
import { SOME_MUTATION } from './mutation-types'

const store = createStore({
  state: { ... },
  mutations: {
    // 我们可以使用 ES2015 风格的计算属性命名功能
    // 来使用一个常量作为函数名
    [SOME_MUTATION] (state) {
      // 修改 state
    }
  }
})

用不用常量取决于你——在需要多人协作的大型项目中,这会很有帮助。但如果你不喜欢,你完全可以不这样做。

4. Action - 异步提交

Action | Vuex (vuejs.org)

  • 官方解释

Action 类似于 mutation,不同在于:

1.	`Action `提交的是 `mutation`,而不是直接变更状态`state`。
2.	`Action `可以包含任意**异步操作**。

Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,因此你可以调用 context.commit 提交一个 mutation,或者通过 context.statecontext.getters 来获取 state 和 getters。当我们在之后介绍到 Modules 时,你就知道 context 对象为什么不是 store 实例本身了

  • 提交载荷(Payload)

    异步提交和前面一样 传入的载荷一般是个对象

  mutations:{
    // 更新收货地址  外界传入一个 地址  更新当前state 中的对象
    updateAddress(state, address){
      state.address = address
      // 多个方法下 这样调用
      this.commit('saveAddressToStroage')
    },
    
    saveAddressToStroage(state){
      uni.setStorageSync('address',JSON.stringify(state.address))
    }
  }  
  // 在大多数情况下,载荷应该是一个对象,这样可以包含多个字段并且记录的 mutation 会更易读
  actions: {
      updateAddressSync(context, payload){
          context.commit('updateAddress', payload)
      }
  }

Action 通过 store.dispatch 方法触发:

// 以载荷形式分发
store.dispatch('updateAddressSync', address) //address 是个对象
// 以对象形式分发
store.dispatch({
  type: 'updateAddressSync',
  address: {
      ...
  }
})

5. Modules - 模块化

Module | Vuex (vuejs.org)

为什么要使用模块化?

  • 官方解释

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

    为了解决以上问题,Vuex 允许我们将 store 分割成模块(module)。每个模块拥有自己的 state、mutation、action、getter、甚至是嵌套子模块——从上至下进行同样方式的分割

可以全部写在 store.js 中

const moduleA = {
  state: () => ({ ... }),
  mutations: { ... },
  actions: { ... },
  getters: { ... }
}

const moduleB = {
  state: () => ({ ... }),
  mutations: { ... },
  actions: { ... }
}

const store = createStore({
  modules: {
    a: moduleA,
    b: moduleB
  }
})

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

也可以用导入的方式

  • store.js
import Vue from 'vue'
import Vuex from 'vuex'

// 1. 导入user 的 vuex 模块
import moduleUser from './user.js'

Vue.use(Vuex)

const store = new Vuex.Store({
  // TODO:挂载 store 模块
  modules: {
    // 2. 挂载 user 的 vuex 模块,模块内成员的访问路径被调整为 m_user,例如:
    'm_user': moduleUser
  },
})

export default store

  • 创建user.js
export default {
  // 开启命名空间
  namespaced: true,
  
  // 数据节点
  state:() =>({
    // 在本地中拿到信息  若没有 就是空对象
    address:JSON.parse(uni.getStorageSync('address') || '{}')
  }),
  
  // 方法
  mutations:{
    // 更新收货地址
    updateAddress(state, address){
      state.address = address
      // 使用 this.commit 调用方法存储信息到本地
      this.commit('m_user/saveAddressToStroage')
    },
    // 持久化存储address
    saveAddressToStroage(state){
      uni.setStorageSync('address',JSON.stringify(state.address))
    }
  },

  getters:{
    // 计算地址
    addstr(state) {
      if (!state.address.provinceName) return ''
    
      return state.address.provinceName + state.address.cityName + state.address.countyName + state.address.detailInfo
    } 
  }
}
  • 在页面中配置
<script>
  // 1. 按需导入辅助函数
  import {
    mapState,
    mapMutations,
    mapGetters
  } from 'vuex'

  export default {
    data() {
      return {
        // 2. 注释掉 address 对象 使用 m_user 中 address 的对象    
        // address: {}
      };
    },
    computed: {
      // 3. 把 m_user 模块中的 address 对象映射到当前组件中使用, 代替 data 中 address 对象 
      ...mapState('m_user',['address']),
      addstr() {
        if (!this.address.provinceName) return ''

        return this.address.provinceName + this.address.cityName + this.address.countyName + this.address.detailInfo
      }
    },
    methods: {
      // 4. 把 m_user 模块中的 updateAddress 函数映射到当前组件中
      ...mapMutations('m_user',['updateAddress']),
      // 5. 把 m_user 模块中的 addstr getters方法映射到组件中
      ...mapGetters('m_user',['addstr'])
    },
  }
</script>

—— 总结 ——

仅是个人理解,更多更详细的内容还得看Vuex 官网:Vuex 是什么? | Vuex (vuejs.org),若有错误请指出!

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Kaiyue.zhao

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值