Kaloyan Yosifov
Posted on March 10, 2021
Hello everybody 👋
I am reallllllllly tired of writing the same code on every component when making a request. I want to make things simple and my guess is that you want too. Check out my examples to see my tips on such things 😃.
Currently, when we want to get something from an API, we write the code below ... at least I did 😃
<template>
<div class="section-orders">
<ul v-if="!loading && orders.length" class="orders">
<li v-for="order in orders" :key="order.id">{{ order.name }}</li>
</ul>
<span v-if="loading">Loading...</span>
<span v-if="errorMessage">{{ errorMessage }}</span>
</div>
</template>
<script>
/**
* External dependencies.
*/
import axios from 'axios';
import { ref } from '@vue/composition-api';
export default {
name: 'OrdersSection',
setup() {
const errorMessage = ref('');
const loading = ref(false);
const orders = ref([]);
const fetchOrders = async () => {
if (loading.value) {
return;
}
errorMessage.value = '';
try {
loading.value = true;
const response = await axios.get('/orders');
orders.value = response.data;
} catch (error) {
errorMessage.value = 'An error has ocurred!';
} finally {
loading.value = false;
}
};
fetchOrders();
return {
orders,
loading,
errorMessage,
};
},
};
</script>
This is ok if we are only going to use it on one component. But if we want to retrieve the orders in a different component, we can either copy the code above or create a composition function to extract the logic for it.
It can look something like this.
<template>
<div class="section-orders">
<ul v-if="!loading && orders.length" class="orders">
<li v-for="order in orders" :key="order.id">{{ order.name }}</li>
</ul>
<span v-if="loading">Loading...</span>
<span v-if="errorMessage">{{ errorMessage }}</span>
</div>
</template>
<script>
/**
* Internal dependencies.
*/
import useOrders from '@/components/bank-form/use-orders';
export default {
name: 'OrdersSection',
setup() {
const { loading, errorMessage, orders } = useOrders();
return {
orders,
loading,
errorMessage,
};
},
};
</script>
and the useOrders
composition function:
/**
* External dependencies.
*/
import axios from 'axios';
import { ref } from '@vue/composition-api';
export default function useOrders() {
const errorMessage = ref('');
const loading = ref(false);
const orders = ref([]);
const fetchOrders = async () => {
if (loading.value) {
return;
}
errorMessage.value = '';
try {
loading.value = true;
const response = await axios.get('/orders');
orders.value = response.data;
} catch (error) {
errorMessage.value = 'An error has ocurred!';
} finally {
loading.value = false;
}
};
fetchOrders();
return {
orders,
loading,
errorMessage,
};
}
But after some time you need to do the same logic for another request and it becomes tedious to write the same, "loading, errorMessage and data" state.
This is so much easy with @cytools/vue-query
.
Here is an example
<template>
<div class="section-orders">
<ul v-if="!isLoading && orders.length" class="orders">
<li v-for="order in orders" :key="order.id">{{ order.name }}</li>
</ul>
<span v-if="isLoading">Loading...</span>
<span v-if="error">{{ error }}</span>
</div>
</template>
<script>
/**
* Internal dependencies.
*/
import axios from 'axios';
import { useQuery } from '@cytools/vue-query';
export default {
name: 'OrdersSection',
setup() {
const { isLoading, error, data: orders } = useQuery(
'orders',
async () => {
return (await axios.get('/orders')).data;
},
{
defaultData: [],
},
);
return {
orders,
isLoading,
error,
};
},
};
</script>
We've done everything with less code and get free caching of the data based on the key.
Here is a link to the library for more details -- https://github.com/cytools/vue-query
There is a lot more fun than just the example above.
Posted on March 10, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.