Carl Wirkus
Carl Wirkus

Reputation: 643

Vuex Mutation Best Practices - Merging State with Payload

I'm trying to avoid the following code with Vuex.

//Product.js
const mutations = {
    SET_PRODUCT_DATA(state, product) {
        state.title = product.title
        state.variantId = product.variantId
        state.handle = product.handle
        state.tags = product.tags
        state.productType = product.productType
        state.featureImage = product.featureImage
        state.vendor = product.vendor
        state.description = product.description
        state.images = product.images
        state.presentmentPrices = product.presentmentPrices
        state.available = product.available
        state.quantity = product.quantity
        state.length = product.length
        state.width = product.width
        state.height = product.height
        state.weight = product.weight
        state.features = product.features
        state.sizeMeta = product.sizeMeta
        state.swatch = product.swatch
    },
}

However if I try to merge the state object with my payload it doesn't work (I believe this is to do with how vue handles reactivity but I don't fully understand that yet).

const mutations = {
    SET_PRODUCT_DATA(state, product) {
        state = { ...state, ...product} //doesn't work
    },
}

I also want to avoid defining an object within my state like 'data' where I would assign this payload. This seams like unnecessary nesting.

const mutations = {
    SET_PRODUCT_DATA(state, product) {
        state.data = product //avoid 🤮
    },
}

Upvotes: 3

Views: 1388

Answers (3)

Anatoly
Anatoly

Reputation: 22813

If you pass an object with already existing state props only then you can use Object.assign:

const mutations = {
    SET_PRODUCT_DATA(state, product) {
        Object.assign(state, product)
    },
}

Upvotes: 3

Igor Moraru
Igor Moraru

Reputation: 7739

If product object keys will always be the same as modified state properties, you can chose to set each property with set() method, which modify a state root property while preserving reactivity:

import Vue from 'vue'

SET_PRODUCT_DATA(state, product) {
    Object.keys(product).forEach(key => {
      Vue.set(state, key, product[key])
    }
},

Also, merging state with the product object, using spread operator does not work due to the fact that it clones the entire state into a new object, which evidently loses the reactivity of the existing state.

Upvotes: 4

Radu Diță
Radu Diță

Reputation: 14211

You can use Object.keys and iterate over them to copy all the values

const mutations = {
    SET_PRODUCT_DATA(state, product) {
        Object.keys(product)
              .forEach(key => {
                state[key] = product[key]
    },
}

Upvotes: 3

Related Questions