Vue.js Vuex状態管理

Vuexによる状態管理

Vuexを使ってグローバルな状態管理を実装しよう。商品リストとカートの状態を一元管理します。

タスク

Vuexストアの作成

State、Actions、Mutations、Gettersを定義しよう

コンポーネントでの状態利用

$store.stateや$store.dispatchを使って状態を操作しよう

Gettersでの計算

合計金額をGettersで計算しよう

ヒント

VuexのState、Actions、Mutations、Gettersを使って、コンポーネント間で状態を共有しましょう。

参考コード

// Vuexストアの作成
const store = Vuex.createStore({
  state() {
    return {
      products: [
        { id: 1, name: '商品A', price: 1000 },
        { id: 2, name: '商品B', price: 2000 },
        { id: 3, name: '商品C', price: 1500 }
      ],
      cart: []
    }
  },
  mutations: {
    addToCart(state, product) {
      const existingItem = state.cart.find(item => item.id === product.id)
      if (existingItem) {
        existingItem.quantity++
      } else {
        state.cart.push({ ...product, quantity: 1 })
      }
    },
    removeFromCart(state, productId) {
      state.cart = state.cart.filter(item => item.id !== productId)
    },
    updateQuantity(state, { productId, quantity }) {
      const item = state.cart.find(item => item.id === productId)
      if (item) {
        item.quantity = quantity
      }
    }
  },
  actions: {
    addProduct({ commit }, product) {
      commit('addToCart', product)
    },
    removeProduct({ commit }, productId) {
      commit('removeFromCart', productId)
    },
    updateProductQuantity({ commit }, payload) {
      commit('updateQuantity', payload)
    }
  },
  getters: {
    cartTotal: (state) => {
      return state.cart.reduce((total, item) => total + (item.price * item.quantity), 0)
    }
  }
})

// 商品リストコンポーネント
const ProductList = {
  computed: {
    products() {
      return this.$store.state.products
    }
  },
  methods: {
    addToCart(product) {
      this.$store.dispatch('addProduct', product)
    }
  },
  template: `
    <div>
      <div v-for="product in products" :key="product.id" class="product-item">
        <h4>{{ product.name }}</h4>
        <p>¥{{ product.price }}</p>
        <button class="btn" @click="addToCart(product)">カートに追加</button>
      </div>
    </div>
  `
}

// ショッピングカートコンポーネント
const ShoppingCart = {
  computed: {
    cart() {
      return this.$store.state.cart
    },
    total() {
      return this.$store.getters.cartTotal
    }
  },
  methods: {
    removeItem(productId) {
      this.$store.dispatch('removeProduct', productId)
    },
    updateQuantity(productId, quantity) {
      this.$store.dispatch('updateProductQuantity', { productId, quantity })
    }
  },
  template: `
    <div>
      <div v-for="item in cart" :key="item.id" class="cart-item">
        <h4>{{ item.name }}</h4>
        <p>¥{{ item.price }} × {{ item.quantity }}</p>
        <button class="btn" @click="updateQuantity(item.id, item.quantity + 1)">+</button>
        <button class="btn" @click="updateQuantity(item.id, Math.max(0, item.quantity - 1))">-</button>
        <button class="btn" @click="removeItem(item.id)">削除</button>
      </div>
      <div class="total">合計: ¥{{ total }}</div>
    </div>
  `
}

// アプリケーションの作成
const app = Vue.createApp({
  components: {
    'product-list': ProductList,
    'shopping-cart': ShoppingCart
  }
})

// Vuexストアをアプリケーションに追加
app.use(store)

// マウント
app.mount('#app')

プレビュー

見本