[Express+Vue 搭建電商網站] 13 使用 Axios 取得 API 資料
使用 Express + Vue 搭建一個電商網站 - 使用 Axios 取得 API 資料
使用 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
是從組件分派的事件或動作名稱,接收兩個參數 context
、payload
context
具有跟 store
相同的方法與屬性,可以透過 context.commit
來提交一個 mutation
或是透過 context.state
和 context.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,
});
})
}
}
});
我們總共做了幾件事情
- 導入 axios,定義了後端 API 的網址到
API_BASE
- 刪除 store 中的假資料,清空
products
陣列 - mutations 增加了
ALL_PRODUCTS
和ALL_PRODUCTS_SUCCESS
方法< 用來處理撈取後端資料的載入狀態以及資料 - 最後加入了
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
方法觸發名叫 allProducts
的 action
為什麼我們這邊不使用 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