Demo repo: https://code.area17.com/antoine/behaviors-state-management/
Key Concepts
Create your store with actions, mutations and an initial state:
import Store from '@area17/a17-helpers/src/utility/store'
const actions = {
addItem(context, payload) {
context.commit('addItem', payload)
},
clearItem(context, payload) {
context.commit('clearItem', payload)
},
empty(context, payload) {
context.commit('empty', payload)
}
}
const mutations = {
addItem(state, payload) {
const newCart = state.cart
newCart.push(payload)
state.cart = newCart
return state
},
clearItem(state, payload) {
const newCart = state.cart
newCart.splice(payload.index, 1)
state.cart = newCart
return state
},
empty(state, payload) {
state.cart = []
return state
}
}
const initialState = {
cart: []
}
export default new Store({ actions, mutations, initialState })
Dispatch changes:
store.dispatch('addItem', { id: '1', title: 'Product 1', price: 50 })
Subscribe to changes:
this.storeObserver = store.subscribe(this.render)
Unsubscribe to changes
this.storeObserver()
Demo Cart
Products
Product 1 - 50€
Product 2 - 200€
Product 3 - 100€
Cart
Nothing in Cart
Total : 0€
This demo cart uses the following behaviors:
import createBehavior from '@area17/a17-helpers/src/utility/createBehavior';
import store from '../store/index.js';
const addToCart = createBehavior(
'addToCart',
{
handleClick() {
store.dispatch('addItem', Object.assign({}, this.options))
},
},
{
init() {
this.$node.addEventListener('click', this.handleClick, false)
},
destroy() {
this.$node.removeEventListener('click', this.handleClick, false)
},
}
);
export default addToCart;
import createBehavior from '@area17/a17-helpers/src/utility/createBehavior';
import store from '../store/index.js';
const cart = createBehavior(
'cart',
{
renderItem(item) {
// Simple templating
return this.$template.innerHTML
.replace(/%title%/gm, item.title ? item.title : '')
.replace(/%price%/gm, item.price ? item.price : '')
.replace(/%id%/gm, item.id ? item.id : '')
.replace(/%img%/gm, item.img ? item.img : '')
},
render() {
// Empty Cart
if(store.state.cart.length === 0) {
this.$node.classList.remove(this.klass)
this.$list.innerHTML = `${this.options.empty}
`
return
}
// Generate cart markup
this.$list.innerHTML = store.state.cart.map(item => {
return this.renderItem(item)
}).join('')
this.$list.querySelectorAll('button').forEach((button, index) => {
button.addEventListener('click', () => {
store.dispatch('clearItem', { index })
})
})
// show extra markup
this.$node.classList.add(this.klass)
}
},
{
init() {
this.klass = 'cart--ready'
this.$template = this.getChild('template')
this.$list = this.$node.firstElementChild
this.storeObserver = store.subscribe(this.render)
},
destroy() {
this.storeObserver() // unsubscribe
},
}
);
export default cart;
import createBehavior from '@area17/a17-helpers/src/utility/createBehavior';
import store from '../store/index.js';
const emptyCart = createBehavior(
'emptyCart',
{
handleClick() {
store.dispatch('empty', {})
},
},
{
init() {
this.$node.addEventListener('click', this.handleClick, false)
},
destroy() {
this.$node.removeEventListener('click', this.handleClick, false)
},
}
);
export default emptyCart;
import createBehavior from '@area17/a17-helpers/src/utility/createBehavior';
import store from '../store/index.js';
const totCart = createBehavior(
'totCart',
{
render() {
this.$node.innerHTML = store.state.cart.reduce( function(a, b){
return a + Number(b.price)
}, 0);
}
},
{
init() {
this.storeObserver = store.subscribe(this.render)
},
destroy() {
this.storeObserver() // unsubscribe
},
}
);
export default totCart;