Vuex: stateの値にpayloadを使う場合の注意事項

vuex@3.1.2

 

Goal: shopping cart の中身を商品のIDごとに管理し、かつ各IDごとの数量を vuex stateに保持したい。また数量が1つずつではなく複数 cart に追加できるものとする。

 

const state = {

  products: []

}

 

const actions = {

  cart_addProduct({state, commit}, items) {

    if(state.products.length) {

      commit('CART_ADD_PRODUCTS', items)

    } else {

      commit('CART_INITIALIZE', items)

    }

  }

}

 

const mutations = {

  'CART_ADD_PRODUCTS' (state, items) {

    for(let i=0; i < items.length; i++) {

      const detectItem = state.products.find((product) => product.id === items[i].id)

      if(detectItem) {

        detectItem.quantity += items[i].quantity

      } else {

        state.products.push({

          name: items[i].name,

          price: items[i].price,

          quantity: items[i].quantity

        })

      }

    }

  },

  'CART_INITIALIZE' (state, items) {

    for(let i=0; i < items.length; i++) {

      state.products.push({

        name: items[i].name,

        price: items[i].price,

        quantity: items[i].quantity

      })

    }

  }

}

 

ここで

state.products.push(items[i]) のようにmutationのpayloadを直接stateに代入すると値がpayload参照型になってしまいquantityの+= item[i].quantityの部分で意図した値が取得できなくなる。

detectItem.quantity += items[i].quantityで加算ではなく、items[i].quantityが2倍された値が返値になる

そのため同一の値ではあるがオブジェクトをわざわざ成型している。

例えば

'CART_INITIALIZE' で state.products.push(items[i]) とし、

'CART_ADD_PRODUCTS' (state, items) {

  // do nothing

}

とした場合、

cart_addProduct(item) =>  CART_INITIALIZE => cart_addProduct(item) => CART_ADD_PRODUCTS

ここでCART_ADD_PRODUCTSはdo nothing にもかかわらずitemのプロパティが2度目のcart_addProduct(item) のitemのプロパティに勝手に更新される。

 

結論)

payloadがオブジェクトの場合、直接stateに代入しないでpayloadを使って新しくオブジェクトを作りstateに代入する。