vue——vuex学习

vue——vuex学习

简介

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

  1. 组件Vue Component通过dispatch来调用actions提供的方法

  2. 而actions除了可以和api打交道外,还可以通过commit来调mutations提供的方法

  3. 最后mutaions将数据保存到state中

  4. 当然,Vue Components还以通过getters提供的方法获取state中的数据

Vuex和普通全局变量的区别

Vuex 和普通全局对象有以下两点不同:

  1. Vuex 的状态存储是响应式的。当 Vue 组件从 store 中读取状态的时候,若 store 中的状态发生变化,那么相应的组件也会相应地得到高效更新。

  2. 你不能直接改变 store 中的状态。改变 store 中的状态的唯一途径就是显式地提交 (commit) mutation。这样使得我们可以方便地跟踪每一个状态的变化,从而让我们能够实现一些工具帮助我们更好地了解我们的应用。

vuex使用场景

假设有这样一个场景:我们有一个父组件,同时包含两个子组件。父组件可以很容易的通过使用 props 属性来向子组件传递数据。

但是问题来了,当我们的两个子组件如何和对方互相通信的? 或者子组件如何传递数据给他父组件的?在我们的项目很小的时候,这个两个问题都不会太难,因为我们可以通过事件派发和监听来完成父组件和子组件的通信。

随着我们项目的增长:

  • 保持对所有的事件追踪将变得很困难。到底哪个事件是哪个组件派发的,哪个组件该监听哪个事件?

  • 项目逻辑分散在各个组件当中,很容易导致逻辑的混乱,不利于我们项目的维护。

  • 父组件将变得和子组件耦合越来越严重,因为它需要明确的派发和监听子组件的某些事件。

注意:虽然将所有的状态放到 Vuex 会使状态变化更显式和易调试,但也会使代码变得冗长和不直观。如果有些状态严格属于单个组件,最好还是作为组件的局部状态。你应该根据你的应用开发需要进行权衡和确定。

Vuex的语法学习

// 官方学习地址
https://vuex.vuejs.org/zh/guide/strict.html
// 比较棒的讲解
https://juejin.im/entry/59191b6b0ce4630069f6a3ad
// example git地址
https://github.com/vuejs/vuex/tree/dev/examples/shopping-cart

四大核心模块:

  1. state: 状态,state其实是数据状态管理对象,在这里你可以初始化一些你想要的数据。

  2. getter: 获得者,getter是对state的数据对象的读取,getters从表面是获得的意思,可以把他看作在获取数据之前进行的一种再编辑,相当于对数据的一个过滤和加工。getters就像计算属性一样,getter 的返回值会根据它的依赖被缓存起来,且只有当它的依赖值发生了改变才会被重新计算

  3. Actions:行动,Actions里面我们可以定义我们想执行异步的方法,在这里它并不会立即去执行,而是在页面中去dispatch这个方法,提交mutations,而不是直接去改变状态,在页面中有两种方式去做派发,第一种 this.$store.dispatch('xxx') 第二种 可以使用mapActions 辅助函数将组件的 methods 映射为 store.dispatch 调用(Demo中有体现)

  4. mutations: 突变,mutations里面可写很多的改变状态的方法,也就是像翻译一样,可以改变state里面的数据,试讲state的里面数据发生改变的唯一方式。

Vuex相关语法

对象展开运算符...

mapState 函数返回的是一个对象。我们如何将它与局部计算属性混合使用呢?通常,我们需要使用一个工具函数将多个对象合并为一个,以使我们可以将最终对象传给 computed 属性。

computed: {
  localComputed () { /* ... */ },
  // 使用对象展开运算符将此对象混入到外部对象中
  ...mapState({
    // ...
  })
}

mapState 辅助函数

获取多个状态时候,使用 mapState 辅助函数帮助我们生成计算属性。

当映射的计算属性的名称与 state 的子节点名称相同时,我们也可以给 mapState 传一个字符串数组

computed: mapState([
  // 映射 this.count 为 store.state.count
  'count'
])

getters和mapGetters 辅助函数

Getter 接受 state 作为其第一个参数:

const getters={
  counte:(state)=>{
    return state.count+=100
  }
}

mapGetters 辅助函数仅仅是将 store 中的 getter 映射到局部计算属性:

computed: {
  // 使用对象展开运算符将 getter 混入 computed 对象中
    ...mapGetters([
      'doneTodosCount',
      'anotherGetter',
      // ...
    ])
  }

Actions

Action 函数接受一个与 store 实例具有相同方法和属性的 context 对象,因此可以调用 context.commit 提交一个 mutation。

mutation 必须同步执行,Action 就不受约束!我们可以在 action 内部执行异步操作。

actions: {
  incrementAsync ({ commit }) {
    setTimeout(() => {
      commit('increment')
    }, 1000)
  }
}

Vuex使用

基础actions,mutations,state的使用

// store.js文件
import Vue from 'vue'
import Vuex from 'vuex'

Vue.use(Vuex);

const state = {
  count: 3
}

const mutations = {
  add(state, n) {
    state.count += n ;
  },
  reduce(state) {
    state.count--;
  }
}

const getters = {
  count: (state) => {
    return (state.count+ 100)
  }
}

const actions = {
  addAction(context) {
    context.commit('add', 5);
    // 异步输出
    setTimeout(() => {
      context.commit('reduce')
    }, 1000)
  },
  reduceAction({
    commit
  }) {
    commit('reduce');
  },
}

let store = new Vuex.Store({
 	state,
  mutations,
  getters,
  actions
});

export default store;


// 使用vue文件使用
  <div class="container">
    123123
    <h2>{{msg}}</h2>
    <h2>{{$store.state.count}}:{{count}}</h2>
    <p>
      <button @click="$store.commit('add',10)">加1</button>
      <button @click="reduce()">减一</button>
    </p>
    <p>
      <button @click="addAction">加1</button>
      <button @click="reduceAction">减一</button>
    </p>
  </div>
</template>

<script>
import store from "../../vuex/store";
import { mapState, mapMutations, mapGetters, mapActions } from "vuex";
export default {
  data() {
    return {
      msg: "hello"
    };
  },
  store,
  computed: {
    ...mapState(['count']),
    ...mapGetters(["count"])
    // count(){
    //   return this.$store.state.getters.count;
    // }
  },
  methods: {
    ...mapMutations(['add','reduce']),
    ...mapActions(['addAction','reduceAction'])
  },
  created() {}
};
</script>

复杂结构module的用法

// cart.js
import shop from '../../api/shop'

// initial state
// shape: [{ id, quantity }]
const state = {
  items: [],
  checkoutStatus: null
}

// getters
const getters = {
  cartProducts: (state, getters, rootState) => {
    return state.items.map(({ id, quantity }) => {
      const product = rootState.products.all.find(product => product.id === id)
      return {
        title: product.title,
        price: product.price,
        quantity
      }
    })
  },

  cartTotalPrice: (state, getters) => {
    return getters.cartProducts.reduce((total, product) => {
      return total + product.price * product.quantity
    }, 0)
  }
}

// actions
const actions = {
  checkout ({ commit, state }, products) {
    const savedCartItems = [...state.items]
    commit('setCheckoutStatus', null)
    // empty cart
    commit('setCartItems', { items: [] })
    shop.buyProducts(
      products,
      () => commit('setCheckoutStatus', 'successful'),
      () => {
        commit('setCheckoutStatus', 'failed')
        // rollback to the cart saved before sending the request
        commit('setCartItems', { items: savedCartItems })
      }
    )
  },

  addProductToCart ({ state, commit }, product) {
    commit('setCheckoutStatus', null)
    if (product.inventory > 0) {
      const cartItem = state.items.find(item => item.id === product.id)
      if (!cartItem) {
        commit('pushProductToCart', { id: product.id })
      } else {
        commit('incrementItemQuantity', cartItem)
      }
      // remove 1 item from stock
      commit('products/decrementProductInventory', { id: product.id }, { root: true })
    }
  }
}

// mutations
const mutations = {
  pushProductToCart (state, { id }) {
    state.items.push({
      id,
      quantity: 1
    })
  },

  incrementItemQuantity (state, { id }) {
    const cartItem = state.items.find(item => item.id === id)
    cartItem.quantity++
  },

  setCartItems (state, { items }) {
    state.items = items
  },

  setCheckoutStatus (state, status) {
    state.checkoutStatus = status
  }
}

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


// ShoppingCart.vue
<template>
  <div class="cart">
    <h2>Your Cart</h2>
    <p v-show="!products.length"><i>Please add some products to cart.</i></p>
    <ul>
      <li
        v-for="product in products"
        :key="product.id">
        {{ product.title }} - {{ product.price | currency }} x {{ product.quantity }}
      </li>
    </ul>
    <p>Total: {{ total | currency }}</p>
    <p><button :disabled="!products.length" @click="checkout(products)">Checkout</button></p>
    <p v-show="checkoutStatus">Checkout {{ checkoutStatus }}.</p>
  </div>
</template>

<script>
import { mapGetters, mapState } from 'vuex'

export default {
  computed: {
    ...mapState({
      checkoutStatus: state => state.cart.checkoutStatus
    }),
    ...mapGetters('cart', {
      products: 'cartProducts',
      total: 'cartTotalPrice'
    })
  },
  methods: {
    checkout (products) {
      this.$store.dispatch('cart/checkout', products)
    }
  }
}
</script>

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值