
A Full Day of Vue.js

04. State Management & Vuex
What we've learned so far...
-
The Vue Instance is the starting point of all Vue applications, and is mounted to a DOM element.
-
Vue applications are data-driven.
-
Mustache Syntax can be used to bind data on to text content.
-
Directives tell DOM elements to act in a certain way.
-
v-bind:
-
v-on:
-
v-for:
-
v-model:
-
v-if/v-show:
bind data to HTML attributes
listen and act on DOM events
render a list based on a data source
two-way data binding with form inputs
conditionally render/show a DOM element
What we've learned so far...
-
Methods are evaluated when explicitly called.
-
Computed properties are used to perform more complex calculations/manipulation to data values and are cached.
-
Watchers allow us to react to data changes.
-
Lifecycle hooks are functions that run through the lifecycle of a Vue instance.
-
beforeCreate()/created()
-
beforeMount()/mounted()
-
beforeUpdate()/updated()
-
beforeDestroyed()/destroyed()
What we've learned so far...
-
Vue Components are self-contained modules that can group markup, logic, and even styles.
Global Components:
Component Variables:
Single File Components
Vue.component('name-of-component', {});
const nameOfComponentObject = {};
-
Single File Components allow us to define HTML/CSS and JS of a component within a single .vue file
<template> section - HTML
<script> section - JS
<style> section - CSS
-
Props (data) can only be passed downwards in a single direction (parent - child - etc.).
-
vue-cli can help facilitate the rapid building and developing of Vue applications.
npm install -g @vue/cli
vue create name_of_project
What we've learned so far...
Components are the building blocks of Vue applications
1
Whether Global or Single-File components
Every Vue component contains a data() function
2
data() prepares the component to be reactive
What we've learned so far...
Data (i.e. props) can only be passed downwards
3
Downwards = Uni-directional (parent -> child -> grandchild -> etc.)
What we've learned so far...
Parent Component
Child Component
props
What we've learned so far...
<template>
<div>
<ChildComponent :numbers="numbers" />
</div>
</template>
<script>
import ChildComponent from "./ChildComponent";
export default {
name: "ParentComponent",
data() {
return {
numbers: [1, 2, 3]
};
},
components: {
"ChildComponent": ChildComponent
}
};
</script>
<template>
<div>
<h2>{{ numbers }}</h2>
</div>
</template>
<script>
export default {
name: "ChildComponent",
props: ['numbers']
};
</script>
numbers
ParentComponent.vue
ChildComponent.vue
What if we needed to communicate in the opposite direction?
🤔
e.g. Have ChildComponent introduce a new number in ParentComponent's numbers array
Custom Events can allow us to have child components notify/communicate with parent components.
Custom Events
Custom Events
this.$emit('name-of-event', {});
Reference to Vue Instance
Data
Vue Custom Events behave very similar to native JavaScript Custom Events
Custom Events
<template>
<div>
<ChildComponent
:numbers="numbers"
@number-added="numbers.push($event)"
/>
</div>
</template>
<script>
import ChildComponent from "./ChildComponent";
export default {
name: "ParentComponent",
data() {
return {
numbers: [1, 2, 3]
};
},
components: {
"ChildComponent": ChildComponent
}
};
</script>
<template>
<div>
<h2>{{ numbers }}</h2>
<input v-model="number" type="number" />
<button @click="$emit('number-added', Number(number))">
Add new number
</button>
</div>
</template>
<script>
export default {
name: "ChildComponent",
props: {
numbers: Array
},
data() {
return {
number: 0
};
}
};
</script>
ParentComponent.vue
ChildComponent.vue
Custom Events
Parent Component
Child Component
props
custom events
Custom Events
Parent Component
Child Component #1
Child Component #2
?
Custom Events
this.$emit('name-of-event', {});
<child-component
@name-of-event="triggerMethod">
</child-component>
Child Component
Parent Component
With standard custom events; the custom event listener needs to be declared where the child component is being rendered in the parent.
Custom Events
3 ways to managing data (i.e. state) in a Vue application.
Using a global EventBus
Using simple state management
Using Vuex
1.
2.
3.
EventBus
An Event Bus is a Vue instance that is used to enable isolated components to subscribe and publish custom events between one another.
EventBus
EventBus = new Vue();
window.EventBus
import Vue from 'vue';
export const EventBus = new Vue();
An EventBus can have isolated components communicate by being made global.

EventBus

EventBus
import Vue from 'vue';
export const EventBus = new Vue();
<template>
<div>
<input v-model="number" type="number" />
<button @click="addNumber">
Add new number
</button>
</div>
</template>
<script>
import { EventBus } from "../event-bus.js";
export default {
name: "NumberSubmit",
data() {
return {
number: 0
};
},
methods: {
addNumber() {
EventBus.$emit("number-added", Number(this.number));
}
}
};
</script>
<template>
<div>
<h2>{{ numbers }}</h2>
</div>
</template>
<script>
import { EventBus } from "../event-bus.js";
export default {
name: "NumberDisplay",
data() {
return {
numbers: [1, 2, 3]
};
},
created() {
EventBus.$on("number-added", number => {
this.numbers.push(number);
});
}
};
</script>
NumberSubmit.vue
NumberDisplay.vue
event-bus.js


EventBus
Parent Component
Child Component #1
Child Component #2
EventBus
EventBus
EventBus
Parent
Component #1
Component #2
Component #3
Component #2.1
Component #1.2
Component #1.1
😭
EventBus
EventBus
An Event Bus (or using this.$root) is not the recommended way of managing application wide state.
Simple State Management
State Management is the management of application-level data
Simple State Management
Parent Component
Child Component
What we've seen so far...
Could we have all child components notify the parent to make changes, without using events?
Simple State Management
Instead of having everything centralized in the parent component - we can externalize this to a store
store = {
state: {
numbers: [1, 2, 3]
},
}
addNumber(number) {
this.state.numbers.push(number);
}
Simple State Management
export const store = {
state: {
numbers: [1, 2, 3]
},
addNumber(newNumber) {
this.state.numbers.push(newNumber);
}
};
<template>
<div>
<h2>{{ storeState.numbers }}</h2>
</div>
</template>
<script>
import { store } from "../store.js";
export default {
name: "NumberDisplay",
data() {
return {
storeState: store.state
};
}
};
</script>
<template>
<div>
<input v-model="number" type="number" />
<button @click="addNumber">
Add new number
</button>
</div>
</template>
<script>
import { store } from "../store.js";
export default {
name: "NumberSubmit",
data() {
return {
number: 0
};
},
methods: {
addNumber() {
store.addNumber(Number(this.number));
}
}
};
</script>
store.js
NumberDisplay.vue
NumberSubmit.vue
Simple State Management
Store
NumberSubmit
NumberDisplay
Dispatches store.addNumber()
Triggers updates to view
Simple State Management
Store state is mutated directly.
store = {
state: {
numbers: [1, 2, 3]
},
addNumber(number) {
this.state.numbers.push(number);
}
}
Simple State Management
We want to keep state mutations within the store.
store = { state: { numbers: [1, 2, 3] }, addNumber(number) { this.state.numbers.push(number); },
removeLastNumber() { this.state.numbers.pop(); },
reverseNumbers() { this.state.numbers.reverse(); } }
Simple State Management
Parent
Component #1
Component #2
Component #3
Component #2.1
Component #1.2
Component #1.1
😭
Store
Simple State Management
export const store = {
state: {
numbers: [1, 2, 3]
},
addNumber(newNumber) {
this.state.numbers.push(newNumber);
}
};
<template>
<div>
<h2>{{ storeState.numbers }}</h2>
</div>
</template>
<script>
import { store } from "../store.js";
export default {
name: "NumberDisplay",
data() {
return {
storeState: store.state
};
}
};
</script>
<template>
<div>
<input v-model="numberInput" type="number" />
<button @click="addNumber">
Add new number
</button>
</div>
</template>
<script>
import { store } from "../store.js";
export default {
name: "NumberSubmit",
data() {
return {
number: 0
};
},
methods: {
addNumber() {
store.addNumber(Number(this.number));
}
}
};
</script>
store.js
NumberDisplay.vue
NumberSubmit.vue
Action
Mutation
Getter
Simple State Management
This brings us very close to the Flux-like architecture of managing client-side state.
Vuex
Vuex is a flux-like, state management library built solely for use with Vue
Vuex
Dispatcher
Action
Store
View
Vuex
npm install vuex
Vuex
Vue.use(Vuex);
import Vue from 'vue';
import Vuex from 'vuex';
Vuex
const store = new Vuex.Store({
state,
mutations,
actions,
getters
});
new Vue({
el: '#app',
store,
render: h => h(App)
});
Vuex
const state = {
numbers: [1, 2, 3]
}
Vuex
const mutations = {
ADD_NUMBER(state, payload) {
state.numbers.push(payload);
}
}
const mutations = {
ADD_NUMBER(state, payload) {
state.numbers.push(payload);
}
}
state
payload
const mutations = {
ADD_NUMBER(state, payload) {
state.numbers.push(payload);
}
}
Vuex
const actions = {
addNumber(context, number) {
context.commit('ADD_NUMBER', number);
}
}
const actions = {
addNumber(context, number) {
context.commit('ADD_NUMBER', number);
}
}
context
context.state
context.getters
context.commit
const actions = {
addNumber(context, number) {
context.commit('ADD_NUMBER', number);
}
}
Vuex
const getters = {
getNumbers(state) {
return state.numbers;
}
}
state
const getters = {
getNumbers(state) {
return state.numbers;
}
}
const getters = {
getNumbers(state) {
return state.numbers;
}
}
Vuex
With a Vuex Store; Components often do one of two things:
GET State Data
Dispatch actions
GETTERS
STATE
Vuex
In Components, store can be accessed with:
this.$store
this.$store.state
this.$store.dispatch('nameOfAction')
this.$store.getters
this.$store.commit('nameOfMutation')
Vuex
<template>
<div>
<h2>{{ getNumbers }}</h2>
</div>
</template>
<script>
export default {
name: "NumberDisplay",
computed: {
getNumbers() {
return this.$store.getters.getNumbers;
}
}
};
</script>
<template>
<div>
<input v-model="number" type="number" />
<button @click="addNumber">
Add new number
</button>
</div>
</template>
<script>
export default {
name: "NumberSubmit",
data() {
return {
number: 0
};
},
methods: {
addNumber() {
this.$store.dispatch("addNumber", Number(this.number));
}
}
};
</script>
NumberDisplay.vue
NumberSubmit.vue
Vuex

const state = {
numbers: [1, 2, 3]
}
Vuex
methods: {
addNumber() {
this.$store.dispatch('addNumber', Number(this.number));
}
}
NumberSubmit.vue
Vuex
store.js
const actions = {
addNumber(context, number) {
context.commit('ADD_NUMBER', number);
}
}
5
Vuex
store.js
const mutations = {
ADD_NUMBER(state, payload) {
state.numbers.push(payload);
}
}
5
[1,2,3]
Vuex

Vuex
Vuex > simple state management
1. By introducing explicitly defined getters, mutations, and actions
2. Integrating with Vue devtools for time travel debugging
Vuex
What are ways we can scale up a Vuex store?
Vuex - MapState, MapGetters, MapActions
computed: {
numbers() {
return this.$store.state.numbers
}
}
State
computed: {
numbers() {
return this.$store.getters.numbers
}
}
Getters
Actions
methods: {
addNumber() {
this.$store.dispatch('addNumber', Number(this.number));
}
}
Without Helpers
Vuex - MapState, MapGetters, MapActions
computed: mapState({
'numbers'
})
State
Getters
Actions
methods: mapActions({ 'addNumber'
})
With Helpers
computed: mapGetters({
'numbers'
})
Vuex - MapState, MapGetters, MapActions
computed: mapState({
computedNumber: 'numbers'
})
State
Getters
Actions
methods: mapActions({ methodAddNumber: 'addNumber'
})
With Helpers
computed: mapGetters({
computedNumbers:'numbers'
})
app/
components/
cart/
product/
store/
index.js
🛒
Vuex - Modules
const state = {
// ...
}
const mutations = {
// ...
}
const actions = {
// ...
}
const getters = {
// ...
}
export default new Vuex.Store({
state,
mutations,
actions,
getters
});
store/index.js
Vuex - Modules
Vuex - Modules
Vuex Modules allows us to break a store into more manageable fragments
Vuex - Modules
const cartModule = {
state,
mutations,
actions,
getters
}
const productModule = {
state,
mutations,
actions,
getters
}
Vuex - Modules
export default new Vuex.Store({
modules: {
cartModule,
productModule
}
});
Vuex - Modules
By default - actions, mutations, and getters are all registered under the global namespace
this.$store.state.cartModule
this.$store.state.productModule
this.$store.dispatch('name-of-any-action')
this.$store.getters['name-of-any-getter']
namespaced
Not namespaced
Vuex - Modules
namespaced: true,
const cartModule = {
namespaced: true,
state,
mutations,
actions,
getters
}
const cartModule = {
}
const productModule = {
namespaced: true,
state,
mutations,
actions,
getters
}
namespaced: true,
const productModule = {
}
Vuex - Modules
this.$store.state.cartModule
namespaced modules
this.$store.dispatch('cartModule/name-of-action')
this.$store.getters['cartModule/name-of-getter']
...mapGetters([
'cartModule/name-of-getter'
]);
...mapActions([
'cartModule/name-of-action'
]);
Vuex - Modules
store/
index.js
cart/
index.js
product/
index.js
index.js
Vuex - Modules
store/
cart/
index.js
index.js
actions.js
getters.js
mutations.js
product/
index.js
actions.js
getters.js
mutations.js
Vuex - Modules
store
cart
product
state
mutations
actions
getters
state
mutations
actions
getters
Vuex - Modules
store/
cart/
index.js
product/
user/
actions.js
getters.js
index.js
mutations.js
Vuex - Modules
store/
cart/
index.js
product/
user/
shared/
Vuex

EventBus | Simple Store | Vuex
What's the best approach?
Vuex
EventBus
Pro:
Incredibly easy to set-up.
Con:
Unable to track changes as they occur.
Simple Store
Pro:
Relatively easy to establish.
Con:
State and possible state changes aren't explicitly defined.
Vuex
Pro:
The most robust way to manage application level state and integrates with Vue devtools.
Con:
Additional boilerpate and requires Flux-like understanding.
Avoid!
Vuex
- State Management/Vuex Documentation
- Managing State in Vue.js
- The Importance of State Management in Vue: Spotlight Vue
State Management and Vuex - Chapter Summary
Props can be used to pass data from parent components down to child components.
Custom Events allow child components to notify/communicate with parent components.
this.$emit('name-of-event', {});
An Event Bus can enable isolated components to subscribe and publish custom events between one another.
Event Bus is a new Vue instance that's made global:
const EventBus = new Vue();
Simple state management can be performed by creating a store pattern that involves sharing a data store between components.
Store manages application state AND methods responsible in mutating state
Vuex is the flux-like, state management library built solely for use with Vue
Introduces explicitly defined getters, mutations, and actions
Integrates with Vue Devtools for time-travel debugging
State Management and Vuex - Chapter Exercise 💪!
State Management and Vuex - Chapter Exercise 💪!

App
InputComponent
NoteCountComponent
State Management and Vuex - Chapter Exercise 💪!
App
InputComponent
NoteCountComponent
State Management and Vuex - Chapter Exercise 💪!
Custom Events
Have App contain notes array.
InputComponent can submit a custom event upwards to App, to manipulate App data array.
App can pass data array to NoteCountComponent.
Simple Store
Create a simple store.js file that contains state.notes array and possible mutation.
InputComponent can call a method that acts on store mutation (action).
NoteCountComponent proxies state.notes value to a local data value (getter).
Vuex
Create a Vuex store.js file that contains state, mutations, actions, and (maybe) getters.
InputComponent will dispatch an action.
NoteCountComponent will return a getter/or state value.
Solution 👀
Solution 👀
Solution 👀
🎉
A Full Day of Vue.js Workshop - 04 State Management and Vuex
By djirdehh
A Full Day of Vue.js Workshop - 04 State Management and Vuex
- 315