當我們在呼叫 API 後,通常會有很多後續的功能接續運作,例如:更換狀態、顯示錯誤訊息、使用 try catch blocks 等等。來看看這個搜尋範例是怎麼把程式碼抽取出來。

搜尋範例

我們先來看這段程式碼。

/src/App.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
<template>
<div>
Search for <input v-model="searchInput" />
<div>
<p>Loading: {{ loading }}</p>
<p>Error: {{ error }}</p>
<p>Number of events: {{ results }}</p>
</div>
</div>
</template>
<script>
import { ref, watch } from "@vue/composition-api";
import eventApi from "@/api/event.js";

export default {
setup() {
const searchInput = ref("");
const results = ref(null);
const loading = ref(false);
const error = ref(null);
async function loadData(search) {
loading.value = true;
error.value = null;
results.value = null;
try {
results.value = await eventApi.getEventCount(search.value);
} catch (err) {
error.value = err;
} finally {
loading.value = false;
}
}
watch(searchInput, () => {
if(searchInput.value !== "") {
loadData(searchInput);
} else {
results.value = null;
}
});
return { searchInput, results, loading, error };
}
};
</script>

如果在瀏覽器看起來會是這樣。

搜尋範例

程式碼抽取

接下來我們試著把 api 這段抽取出來。

composables/use-promise.js

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
import { ref } from "@vue/composition-api";

export default function usePromise(fn) {
const results = ref(null);
const loading = ref(false);
const error = ref(null);
const createPromise = async (...args) => {
loading.value = true;
error.value = null;
results.value = null;
try {
results.value = await fn(...args);
} catch (err) {
error.value = err;
} finally {
loading.value = false;
}
}
return { results, loading, error, createPromise };
}

然後我們把抽取出來的程式碼,替代回原本的 App.js。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<template>
<div>
Search for <input v-model="searchInput" />
<div>
<p>Loading: {{ getEvents.loading }}</p>
<p>Error: {{ getEvents.error }}</p>
<p>Number of events: {{ getEvents.results }}</p>
</div>
</div>
</template>
<script>
import { ref, watch } from "@vue/composition-api";
import eventApi from "@/api/event.js";
import usePromise from "@/composables/use-promise";

export default {
setup() {
const searchInput = ref("");
const getEvents = usePromise(search =>
eventApi.getEventCount(search.value)
);
watch(searchInput, () => {
if(searchInput.value !== "") {
getEvents.createPromise(searchInput);
} else {
getEvents.results.value = null;
}
});
return { searchInput, getEvents };
}
};
</script>

這樣就完成程式碼的抽取替換囉~另外要注意的事,如果用 Vue 2 的話,html 的部分都要再多加 .value 才會抓到值,但如果是直接用 Vue 3 的話,上面程式碼就能直接正常運行。

參考資料