Validate with asyncData/fetch - Commit data from within Validate? - vue.js

If I want to validate the existence of a dynamic resource Nuxt recommends implementing a validate() call within the page component. If that call performs an API request for data in order to validate the existence of the resource, Nuxt documentation states that I can check the Vuex store, but does not explicitly state that I can dispatch an action in order to commit data received by the API request. The store within the validate() method allows calls to dispatch and syncs with the Vuex store just as with asyncData or fetch, but would this be an anti-pattern - committing data to Vuex from within validate()?
You can also check some data in your store for example (filled by nuxtServerInit before action
The need to commit data from within validate() will prevent a duplicate API call within asyncData or fetch to the same resource. As an example,
If I call validate() requesting the existence of a resource and I do not commit that resource's data to Vuex, I may need to request that resource data again from with asyncData or fetch.
validate ({ app, params, store }) {
return app.$axios.get('client/cards', {params: { slug: params.card }})
.then(() => true)
.catch(() => false)
}
Essentially duplicating the same API request, but from within the action:
async fetch ({ params, store }) {
await store.dispatch('card/getCard', params.card)
}

Related

asyncData or fetch method with Parameters in NuxtJs

I'm working on a nuxtjs project, using asyncData and fetch methods but I need to use parameterize url for get requests and the parameters are present in the data property of vue. How will I use it.
....
data(){
return {
param1: "455",
param2: "xyz",
products: []
}
},
asyncData(){
return axio.get(`/api/products?type=${param1}&cat{param2}`).then(response => {
this products = response.data
})
}
The approach I used here for parameterize url is correct? Please also discuss for fetch methods as well
You can't. asyncData hook runs before creating the component, so it doesn't have access to the component instance (because it doesn't exists yet).
asyncData could have access to global properties throught the Nuxt context, such as:
route parameters
vuex store
injected properties with plugins
You could use the fetch hook instead, which does have access to this (the component instance).
The difference is that it won't block the page render on client navigation, so you have to handle the loading state with $fetchState.pending.
fetch () {
return axio.get(`/api/products?type=${this.param1}&cat{this.param2}`).then(response => {
this products = response.data
}

Access data from dispatched action using Vuex 4 and Vue 3 Composition API

In my application I have a Vuex 4 store and a Vue 3 Composition Api setup() method.
In the stores action I use axios to make an api call to get a list of bill payments.
The getAllBills action does not live directly in my Store.js file, it exists as a module.
getAllBills({ commit }) {
BillApiCalls.getBills().then(res => {
commit('GET_ALL_BILLS', res.data)
}).catch(error => console.log(error))
},
Then in my Bill.vue file I have the setup() method and am trying to access the data to be used throughout the same Bill.vue file.
setup () {
//Vuex store
const store = useStore();
const billPayments = store.dispatch('payment/getAllBills').then(res => console.log(res));
}
If I check the console from the above .then() res returns as undefined. If I remove the .then() from the billPayments declaration and just do:
console.log(billPayments)
In the console I get
Promise {<pending>}.
Current Store:
import { bill } from './modules/bill.module';
const store = createStore({
modules: {
bill
}
});
The endpoint is working, if I use Postman all of my data is returned as expected but I am having trouble figuring out how to access that data using a dispatched action with the composition api.
The Vuex 4 docs don't mention how to actually resolve the promise to access the data to be used throughout the same component.
An action isn't generally supposed to return data it acts on, data is a part of the state and should be accessed there; this is what another answer shows:
await store.dispatch('payment/getAllBills')
console.log(store.state.payment.bills);
The action doesn't chain promises so it cannot be correctly used. It should be:
return BillApiCalls.getBills()...
Or prefer async..await together with promise to avoid some common mistakes that can be made with raw promises.

Load async data into the vuex store when Nuxt app loads

I am trialling a project in Nuxt. Liking it so far except I am a little confused as to how to load data from an external async service so that it is available in Vuex from the very first route.
I have tried adding middleware on the default layout to dispatch the store action but I do not see the service being called straight away. Only when I navigate deeper into the routes do I see the action dispatched.
I did something similar in a standard Vue project and added the created method to the App.vue.
Is there a similar way in Nuxt?
What you need is called a fetch.
The fetch method, if set, is called every time before loading the component (only for page components). It will be called server-side once (on the first request to the Nuxt app) and client-side when navigating to further routes.
Warning: You don't have access of the component instance through this inside fetch because it is called before initiating the component.
async fetch({ store }) {
await store.dispatch('your-action')
}
If you need parameter:
async fetch({ store, params }) {
await store.dispatch('your-action', params.id)
}
I gave an example of id. The name of the parameter depends on the name of your page.
_id => params.id
_slug => parmas.slug
...

Call API with Another Api response data in Nuxtjs

Im making a website with Nuxtjs, i want when i open any page of the website to get user information from the server using Axios, and i want to use these information to call another API's from the website.
For example: i will get the User id and Client id from the server and use them on the API URL, lets say i got User id = 5, Client id = 10
i will call another API's and use these informations
http://****/getItems?userid=5&clientid=10
Now my problem is the second API call before the first API finished so i didn't got the user informations yet.
Could you please help me with this issue, note that i want to get the user information on all pages. so if i reload the page in any page i want to get user informations.
So i call the user information API from a Layout and call the other API's from another components.
Thanks.
First you should use Axios module officially provided by Nuxt.js here, https://github.com/nuxt-community/axios-module. They have make the integration between Axios and Nuxt.js easier.
Axios uses promise so you can easily chaining method to do it. Let say you wanna get information from /get/product with data gotten from the url you mention before http://****/getItems?userid=5&clientid=10, you can easily do that like this
this.$axios.$get('/getItems?userid=5&clientid=10')
.then(data => {
// You can use your data received from first request here.
return this.$axios.$post('/get/product', {
id: data.id,
clientId: data.clientId
})
})
.then(data => {
// You can use your data received from second request here.
console.log(data)
})
Explanation
This part,
this.$axios.$get('/getItems?userid=5&clientid=10')
the axios will get the data from the url provided, when the data is received, we can use it within then() block as it accept callback as a parameter.
.then(data => {
// You can use your data received from first url here.
...
})
After that, if you wanna use your data you can easily return the axios request again with proper parameter you wanna send.
return this.$axios.$post('/get/product', {
id: data.id,
clientId: data.clientId
})
And again you can use the data received from second axios request within then() block.
.then(data => {
// You can use your data received from second request here.
console.log(data)
})
Updated
Oke, based on the clarification on the comment section below. We can return the axios promise in first action and then on the second method we can dispatch the first action,
actions: {
callFirst ({ commit }) {
return this.$axios.$get('/get/first')
.then(firstResult => {
commit('SET_FIRST', firstResult)
return firstResult
})
},
callSecond ({ dispatch, commit }) {
return dispatch('callFirst').then(firstResult => {
return this.$axios.$post(`/get/${firstResult.userId}`)
.then(secondResult => {
commit('SET_SECOND', secondResult)
return secondResult
})
})
}
}
Using that way, you just need to put the callSecond() action whereever you want get the second data. And you also don't need to put the callFirst() action on default.vue.

Where do I put my server REST logic in vue / vuex

In a Vue + Vuex application...
I have list of items. When I create a new item in the client, this item should also be created on the server. The server should supply the ID of the new iem.
So we need a round-trip before we can update the state.
Now, do I put this AJAX call in vuex 'actions' or in vuex 'mutations'? What's some best practices here...
I would add another level of abstraction :
You should split your api calls within another / other files and call these methods from your store actions
//store action
import * as apiService from '../api'
export const someAction = ({ commit }) => {
apiService.getXXX()
.then( result => {
commit(SOME_MUTATION, result)
})
.catch( error => {
commit(SOME_ERROR_MUTATION, error)
})
}
In Vuex, mutations are synchronous transactions, so you'll want to do any asynchronous work (like AJAX calls) using actions.