I want to organize my code that API routes and calls are separated from page logic. I want to store results of these API calls in a Pinia Store, and refresh/modify it when I want to.
This is how I would usually do it in a common Vue 3 (somewhat simplified):
// helpers/requests.js
import axios from 'axios';
const someApiCall = function(options) {
return new Promise((resolve, reject) => {
const url = new URL('https://api.publicapis.org/entries');
for (const [key, value] of Object.entries(options)) {
url.searchParams.set(key, value);
}
axios
.get(url.toString())
.then((response) => { return resolve(response.data); })
.catch((e) => { console.log(e); reject(e); });
});
};
export { someApiCall };
// stores/mystore.js
import { defineStore } from 'pinia';
import { someApiCall } from '@/helpers/requests.js';
export const useMyStore = defineStore('myStore', {
state: () => ({
loaded: false,
count: 0,
items: [],
}),
actions: {
// Первоначальная загрузка стора
async init() {
if (this.loaded) { return; }
await this.nextPage();
},
// Подгрузка новой порции участников
async nextPage() {
if (this.loaded && this.items.length >= this.count) { return; }
const data = await someApiCall({
myOption: 'blabla',
});
if (data.results && Array.isArray(data.results)) {
this.count = data.count ? data.count : 0;
this.items = this.items.concat(data.results);
this.loaded = true;
} else {
console.error('Report Error');
console.log(data);
setTimeout(this.nextPage, 5000);
}
},
async refresh() {
this.count = 0;
this.items.length = 0;
this.loaded = false;
await this.nextPage();
},
},
});
// components/MyComponent.vue
<script setup>
import { onMounted, ref } from 'vue';
import { useMyStore } from '@/stores/index.js';
// Store
const myStore = useMyStore ();
// Loading Animation
const isLoading = ref(true);
onMounted(async () => {
await myStore.init();
isLoading.value = false;
});
const loadMore = async () => {
isLoading.value = true;
await myStore.nextPage();
isLoading.value = false;
};
</script>
Now the problem. I want to make sure that data is individual for every person, since data will differ for different users (I must pass a cookie). It is also has to be rendered on server side.
useFetch and useAsyncData work only inside <script setup>, and $fetch seem to work only with APIs located in server/ folder. I have no idea if /server folder may be useful there, since API server is hosted elsewhere - I only have URLs.
I also tried to do this:
myStore.data = useFetch('https://api.publicapis.org/entries');
But it breaks reactivity and looks like a wrong way.
I would like any tips for a proper calls organization in Nuxt 3.
UPD: Seems like $fetch is the solution, since it works outside of <script setup>. I managed to fetch data to Pinia Store and it was rendered at the server side correctly.
I still don't want to close this question since I don't know if it is a good practice and I still welcome any advice.