Byte Ebi's Logo

Byte Ebi 🍤

每天一小口,蝦米變鯨魚

[Express+Vue 搭建電商網站] 13 使用 Axios 取得 API 資料

使用 Express + Vue 搭建一個電商網站 - 使用 Axios 取得 API 資料

Ray

使用 Axios 取得後端 API 的資料

使用 Axios 取得 API 資料

首先先安裝 axios

npm i axios

在 Vuex store 中可以使用 action 屬性
乍看之下跟 mutation 類似,不同的地方在於

  • Action 提交的是 mutation,而不是直接變更狀態
  • Action 可以包含任意異步操作,用於響應 Vue 組件中分派的事件或動作

一個 action 是類似於 (context, payload) => response.data 的函數:

productById(context, payload) {
  // 異步操作,從後端取得資料
  return response.data;
}

其中 productById 是從組件分派的事件或動作名稱,接收兩個參數 contextpayload
context 具有跟 store 相同的方法與屬性,可以透過 context.commit 來提交一個 mutation
或是透過 context.statecontext.getters 來取得 state 和 getters
payload 就是攜帶的參數,可以透過他來執行異步操作,從而取得後端資料並回傳

所以我們可以在 Action 中異步執行 axios 來抓取後端 API 的資料
取得回傳結果後將結果提交給 mutation,並更新使用者端的資料

實現 Action

再次修改 src/store/index.js

import Vue from 'vue';
import Vuex from 'vuex';
import axios from 'axios';

const API_BASE = 'http://localhost:3000/api/v1';

Vue.use(Vuex);

export default new Vuex.Store({
  strict: true,
  state: {
    // bought items
    cart: [],
    // ajax loader
    showLoader: false,
    // selected product
    product: {},
    // all products
    products: [],
    // all manufacturers
    manufacturers: [],
  },
  mutations: {
    ADD_TO_CART(state, payload) {
      const { product } = payload;
      state.cart.push(product)
    },
    REMOVE_FROM_CART(state, payload) {
      const { productId } = payload
      state.cart = state.cart.filter(product => product._id !== productId)
    },
    ALL_PRODUCTS(state) {
      state.showLoader = true;
    },
    ALL_PRODUCTS_SUCCESS(state, payload) {
      const { products } = payload;

      state.showLoader = false;
      state.products = products;
    }
  },
  actions: {
    allProducts({ commit }) {
      commit('ALL_PRODUCTS')

      axios.get(`${API_BASE}/products`).then(response => {
        console.log('response', response);
        commit('ALL_PRODUCTS_SUCCESS', {
          products: response.data,
        });
      })
    }
  }
});

我們總共做了幾件事情

  1. 導入 axios,定義了後端 API 的網址到 API_BASE
  2. 刪除 store 中的假資料,清空 products 陣列
  3. mutations 增加了 ALL_PRODUCTSALL_PRODUCTS_SUCCESS 方法< 用來處理撈取後端資料的載入狀態以及資料
  4. 最後加入了 actions 屬性,定義了 allProducts 函數,用來響應組件的對應事件
    首先提交了 ALL_PRODUCTS mutation,接著在 axios 取得後端資料後提交了 ALL_PRODUCTS_SUCCESS
    並且把取得的資料命名為 products 一併作為 payload 傳入

提示:
可以看到在 allProducts 中我們傳入了 { commit } 參數
這地方使用了解構賦值 const { commit } = context
代替比較長的 context.commit
因為目前我們沒用到其他 context 屬性,所以這麼做是可以的

更新組件

ProductList

src/components/products/ProductList.vue<script> 區塊改成以下

<script>
export default {
  name: "product-list",
  created() {
    if (this.products.length === 0) {
      this.$store.dispatch("allProducts");
    }
  },
  computed: {
    // a computed getter
    products() {
      return this.$store.state.products;
    }
  },
  methods: {
    addToCart(product) {
      this.$store.commit("ADD_TO_CART", {
        product
      });
    }
  }
};
</script>

增加了一個 created() 生命週期方法,在這個組件被建立時判斷使用者端是否有商品資料
若是沒有,則需要跟後端 API 要資料
於是通過 this.$store.dispatch 方法觸發名叫 allProductsaction

為什麼我們這邊不使用 commit 操作 mutation 而是使用 dispatch 呢?
是因為 mutation 必須是一個同步執行的程式,而這邊是一個異步請求
需要使用 dispatch 來操作 Action 進行異步請求

再來是 <template>,我們做部分修改,讓畫面渲染時的資料符合當初後端 API 定義的格式

<p class="product.manufacturer">生產商{{product.manufacturer.name}}</p>

Cart

接著打開 src/views/Cart.vue 頁面,因為上面也有顯示生產商的名稱
同樣把 {{product.manufacturer}} 改成 {{product.manufacturer.name}}

測試結果

首先確認先前的後端 API 專案已經啟動,並且 MongoDB 也在運行中
如果先前在撰寫 API 時你沒有進行測試,則資料庫應該為空。先去加一些資料吧!

完成之後進入前端測試,應該就可以發現商品的資料就是後端 API 傳來的資料
如果不確定的話,可以照著先前的教學,使用 Postman 取得 API 中的商品列表和前端的資料比對
取得的資料和先前一樣,可以加入與移出購物車


專案範例程式碼 GitHub 網址:ray247k/mini-E-commerce

最新文章

Category

Tag