Vuex; the good parts

State, Actions, Getters, Mutations

Responsibilities in state management systems

Vue Components

Actions

State

Mutations

Backend API

Devtools

Dispatch

Commit

Mutate

Render

Vuex

single source of truth for store state

State

Actions

Mutations

Getters

similar to mutations but it commits mutations

the only way to change store state

to compute derived state based on store state.

(is cached)

(can only be sync)

(can be async)

Vending Machine Stock Counter

Vending Machine Stock Counter

Action

Restocking...

Mutation

40

const store = new Vuex.Store({
  state: {
    supply: 40
  },
  actions: {
    restock(context) {
      return context.commit('restock')
    }
  },
  getters: {},
  mutations: {
    restock(state) {
      state.supply--
    }
  }
})

new Vue({
  el: "#vue",
  computed: {
    stock() {
      return $store.state.supply
    }
  },
  data() {
    return {
      stock: 40
    }
  },
  methods: {
    ...
    restock() {
      $store.dispatch('restock')
    }
  },
  template: `
    <div>
      <p class="supply">{{ supply }}</p>
      <div class="actions">
        <button @click="dispense">+</button>
        <button @click="restock">-</button>
      </div>
    </div>
  `,
})
fetchFromInventory
stockItems

Let's rename!

const store = new Vuex.Store({
  state: {
    supply: 30
  },
  actions: {
    fetchFromInventory(context) {
      // make API Call 
      // on successful return, mutate
      // i.e. context.commit("stockItems")
    }
  },
  getters: {},
  mutations: {
    stockItems(state) {
      // update supply
    }
  }
})

new Vue({
  el: "#vue",
  computed: {
    supply() {
      return $store.state.supply
    }
  },
  methods: {
    ...
    restock() {
      $store.dispatch('fetchFromInventory')
    }
  },
  template: `
    <div>
      <p class="supply">{{ supply }}</p>
      <div class="actions">
        <button @click="dispense">+</button>
        <button @click="restock">-</button>
      </div>
    </div>
  `,
})
// fake out API //
let inventory = {
  "chips": {
    stock: 40
  }
}

var pingInventory = function(item) {
  return new Promise(function(resolve, reject) {
    setTimeout(function() {
      resolve(inventory[item]);
    }, 3000);
  });
}

const store = new Vuex.Store({
  state: {
    supply: 30
  },
  actions: {
    fetchFromInventory(context) {
      pingInventory("chips")
        .then(inventory => {
          context.commit('stockItems', inventory.stock)
        })
    }
  },
  getters: {},
  mutations: {
    stockItems(state) {
      // update supply
    }
  }
})

new Vue({
  el: "#vue",
  computed: {
    supply() {
      return $store.state.supply
    }
  },
  methods: {
    ...
    restock() {
      $store.dispatch('fetchFromInventory')
    }
  },
  template: `
    <div>
      <p class="supply">{{ supply }}</p>
      <div class="actions">
        <button @click="dispense">+</button>
        <button @click="restock">-</button>
      </div>
    </div>
  `,
})
fake out an API
call fake API
...

var pingInventory = function(item) {
  return new Promise(function(resolve, reject) {
    setTimeout(function() {
      resolve(inventory[item]);
    }, 3000);
  });
}

const store = new Vuex.Store({
  state: {
    supply: 30
  },
  actions: {
    fetchFromInventory(context) {
      pingInventory("chips")
        .then(inventory => {
          context.commit('stockItems', inventory.stock)
        })
    }
  },
  getters: {},
  mutations: {
    stockItems(state payload) {
      state.supply = payload
    }
  }
})

new Vue({
  el: "#vue",
  computed: {
    supply() {
      return this.$store.state.supply
    }
  },
  methods: {
    ...
    restock() {
      this.$store.dispatch('fetchFromInventory')
    }
  },
  template: `
    <div>
      <p class="supply">{{ supply }}</p>
      <div class="actions">
        <button @click="dispense">+</button>
        <button @click="restock">-</button>
      </div>
    </div>
  `,
})
// fake out API //
let inventory = {
  "chips": {
    stock: 40
  }
}

var pingInventory = function(item) {
  return new Promise(function(resolve, reject) {
    setTimeout(function() {
      resolve(inventory[item]);
    }, 3000);
  });
}

const store = new Vuex.Store({
  state: {
    supply: 30,
    isRestocking: false
  },
  actions: {
    fetchFromInventory(context) {
      context.commit('isRestocking', true)
      pingInventory("chips")
        .then(inventory => {
          context.commit('stockItems', inventory.stock)
        })
        .finally(() => {
          context.commit('isRestocking', false)
        })
    }
  },
  getters: {},
  mutations: {
    stockItems(state) {
      // update supply
    },
    isRestocking(state, payload) {
      state.isRestocking = payload;
    }
  }
})

new Vue({
  el: "#vue",
  computed: {
    supply() {
      return this.$store.state.supply
    },
    isRestocking() {
      return this.$store.state.isRestocking
    }
  },
  methods: {
    ...
    restock() {
      $store.dispatch('fetchFromInventory')
    }
  },
  template: `
    <div>
      <p class="supply">{{ supply }}</p>
      <div class="actions">
        <button @click="dispense">+</button>
        <button @click="restock">-</button>
      </div>
    </div>
  `,
})
create a loading state

Exercise Time!

https://codepen.io/shortdiv/pen/xxGrMLV

Let's create isRestocking state in Vuex that gets toggled on fetchInventory

Vending Machine Stock Counter

Action

Dispensing...

Mutation

6

// fake out API //
let inventory = {
  "chips": {
    stock: 40
  }
}

var pingInventory = function(item) {
  return new Promise(function(resolve, reject) {
    setTimeout(function() {
      resolve(inventory[item]);
    }, 3000);
  });
}

const store = new Vuex.Store({
  state: {
    supply: 30,
    isRestocking: false
  },
  actions: {
    fetchFromInventory(context) {
      context.commit('isRestocking', true)
      pingInventory("chips")
        .then(inventory => {
          context.commit('stockItems', inventory.stock)
        })
        .finally(() => {
          context.commit('isRestocking', false)
        })
    }
  },
  getters: {},
  mutations: {
    stockItems(state) {
      // update supply
    },
    isRestocking(state, payload) {
      state.isRestocking = payload;
    }
  }
})

new Vue({
  el: "#vue",
  computed: {
    supply() {
      return this.$store.state.supply
    },
    isRestocking() {
      return this.$store.state.isRestocking
    }
  },
  methods: {
    ...
    restock() {
      $store.dispatch('fetchFromInventory')
    }
  },
  template: `
    <div>
      <p class="supply">{{ supply }}</p>
      <div class="actions">
        <button @click="dispense">+</button>
        <button @click="restock">-</button>
      </div>
    </div>
  `,
})

single source of truth for store state

State

Actions

Mutations

Getters

similar to mutations but it commits mutations

the only way to change store state

to compute derived state based on store state.

(is cached)

(can only be sync)

(can be async)

Vending Machine Stock Counter

State

Getter

Changing how state is displayed

const store = new Vuex.Store({
  state: {
    supply: 40,
    ...
  },
  actions: {
    fetchFromInventory(context) {
      ...
      context.commit('stockItems', stock.inventory)
    }
  },
  getters: {
    isSupplyLow: state => state.supply < 10
  },
  mutations: {
    stockItems(state, payload) {
      state.supply = 40
    },
    ...
  }
})

new Vue({
  el: "#vue",
  computed: {
    supply() {
      return this.$store.state.supply
    },
    isSupplyLow() {
      return this.$store.getters.isSupplyLow
    }
  },
  methods: {
    ...
    restock() {
      $store.dispatch('fetchFromInventory')
    }
  },
  template: `
    <div>
      <p class="supply">{{ supply }}</p>
      <div class="actions">
        <button @click="dispense">+</button>
        <button @click="restock">-</button>
      </div>
    </div>
  `,
})

Changing how state is displayed

ES

EN

Getter

Switch out the logic to switch language so it's handled in a Vuex getter

Exercise Time!

Vending Machine Stock Counter

Made with Slides.com