I have read using async data or fetch is a better approach in pages in nuxtjs instead of using the created hook.
I am struggling to get my code to work though
I had the following (Which does work fine)
created () {
this.$store.dispatch('cases/getCase', this.$route.params.caseId );
},
But how would I change that to work with the async method instead please, and be able to return more than one state when I need to.
I tried the following
async asyncData ({ params }) {
const thisCase = await this.$store.dispatch('cases/getCase', this.$route.params.caseId );
// constant thisUser
return { thisCase }
// return { thisCase, thisUser}
},
but this generated an error
undefined is not an object (evaluating 'this.$store')
Can anyone tell me what I am doing wrong please
Thanks
this not available in asyncData/fetch. It is even stated in docs in special orange warning.
You do NOT have access of the component instance through this inside
asyncData because it is called before initiating the component.
And again as said in docs
method receives the context object as the first argument, you can use
it to fetch some data and return the component data.
Context is where from you should be getting your store. Here docs for context.
So your code would be
async asyncData ({ params, store }) {
const thisCase = await store.dispatch('cases/getCase', params.caseId )
return { thisCase }
},
Related
I created a map for the array of exercises in my database, and then for each exercise, which is a document reference, I'm getting the data from that document reference and setting it to a state. This is resulting in an infinite loop right now.
If I remove the setExerciseData line, the console logs the exercise object's data that I'm expecting to see. I'm really not sure what the correct way to render the name field from this data is.
{workout.exercises.map((exercise) => {
async function getData(exercise) {
getDoc(exercise).then((doc) => {
console.log(doc.data());
setExerciseData(doc.data());
});
}
getData(exercise);
return (
<Text>{exerciseData.name}</Text>
)
})}
You need to use useEffect() and setState() to be able to render your data. Also, Firebase Firestore is Asynchronous in nature, as a general note, no one should be trying to convert an Async operation into a sync operation as this will cause problems. You need to use an Asynchronous function to fetch data from Firestore. See sample code below:
const getExerciseData = async () => {
const docRef = doc(db, "<collection-name>", '<document-id>')
const docSnap = await getDoc(docRef)
if (docSnap.exists()) {
// console.log("Document data:", docSnap.data())
setExerciseData(docSnap.data())
} else {
// doc.data() will be undefined in this case
console.log("No such document!")
}
}
useEffect(() => {
getExerciseData()
}, [])
return (
<Text>{exerciseData.name}</Text>
)
You could also check my answer on this thread for more use-cases.
I am using Vue2.6 with composition api.
I need to reroute to different pages depends on an api response.
Can someone please guide me, please?
I tried using onBeforeMount but it renders the UI elements then rerouted to the corresponding page to the api response..so I can see a flash of the wrong UI..
setup() {
const myData = 'myData';
onBeforeMount(async () => {
try {
const results = await fetchData();
// do reroute depends on results response
}
} catch (err) {
console.log(err);
}
});
return {
myData,
};
I also tried adding async in the setup method but it errored saying my ref variables "Property or method "myData" is not defined on the instance but referenced during render."
async setup() {
const myData = 'myData';
onMounted(async () => {
try {
const results = await fetchData();
// do reroute depends on results response
}
} catch (err) {
console.log(err);
}
});
return {
myData,
};
It looks like you're trying to handle routing (re-routing) dynamically from inside a component. I can't see the rest of the apps, so can't speak to the validity of such a solution, but would like you dissuade you from doing that. routing logic should, IMO, not be handled in a component. The components should mostly just handle the template and user interaction. By the time you're rendering a component, that API should have been resolved already.
I would recommend to resolve the API response before the route is
even completed. You or use a navigationGuard to resolve the API during the route execution. This functionality is asynchronous, so you can await the response before proceeding.
Alternatively, if you really want to handle it in the component, you will have that delay while the API is resolving, but you can implement some loader animation to improve the experience.
Im using nuxt and vuex. In vuex im getting data:
actions: {
get_posts(ctx) {
axios.get("http://vengdef.com/wp-json/wp/v2/posts").then(post => {
let posts = post.data;
if (!posts.length) return;
let medias_list = "";
posts.forEach(md => {
medias_list += md.featured_media + ","
});
medias_list = medias_list.slice(0, -1);
let author_list = "";
posts.forEach(md => {
author_list += md.author + ","
});
author_list = author_list.slice(0, -1);
axios.all([
axios.get("http://vengdef.com/wp-json/wp/v2/media?include=" + medias_list),
axios.get("http://vengdef.com/wp-json/wp/v2/users?include=" + author_list),
axios.get("http://vengdef.com/wp-json/wp/v2/categories"),
]).then(axios.spread((medias, authors, categories) => {
ctx.commit("set_postlist", {medias, authors, categories} );
})).catch((err) => {
console.log(err)
});
})
}
},
In vuex state i have dynamic postlist from exaple below.
How i can use it in Nuxt?
In nuxt i know async fetch and asyncData.
async fetch () {
this.$store.dispatch("posts/get_posts");
}
Thats not working.
How i can say to nuxt, wait loading page, before vuex actions loading all data?
As you already mentioned there are:
fetch hook
asyncData
And differences are well described here
The reason why your code is not working might be in your store action.
It should return a promise, try to add return before axios get method ->
get_posts(ctx) {
return axios.get(...
// ...
And then, on your page:
async fetch () {
await this.$store.dispatch("posts/get_posts");
}
Also, in comment above you're saying that you dont want to commit data in store:
...load page only after vuex, i dont need to pass data in vuex
But you do it with this line:
ctx.commit("set_postlist", {medias, authors, categories} );
if you dont want to keep data in store, just replace line above with:
return Promise.resolve({ medias, authors, categories })
and get it on your page:
async fetch () {
this.posts = await this.$store.dispatch("posts/get_posts");
// now you can use posts in template
}
Misread the actual question, hence the update
With Nuxt, you can either use asyncData(), the syntax will change a bit tho and the render will be totally blocked until all the calls are done.
Or use a combo of fetch() and some skeletons to make a smooth transition (aka not blocking the render), or a loader with the $fetchState.pending helper.
More info can be found here: https://nuxtjs.org/docs/2.x/features/data-fetching#the-fetch-hook
Older (irrelevant) answer
If you want to pass a param to your Vuex action, you can call it like this
async fetch () {
await this.$store.dispatch('posts/get_posts', variableHere)
}
In Vuex, access it like
get_posts(ctx, variableHere) {
That you can then use down below.
PS: try to use async/await everywhere.
PS2: also, you can destructure the context directly with something like this
get_posts({ commit }, variableHere) {
...
commit('set_postlist', {medias, authors, categories})
}
I'm using The Strain API which has a search query that gets all the strains in its database. It says to use this sparingly as it requires a lot of computing power. My question is: can I call it once in the App component life cycle hook, save the response in the App data(), and cache it somehow so that if the data.object.length != 0, it doesn't try calling it again? Then I could pass it as a prop to any other component that needs it. Sorry, new to VueJs and programming.
the best thing in my opinion is to keep the calculated data in a service, so that you in your mounted component simply call the getData (), imported from the StrainService.js
// StrainService.js
let response = null;
const getData = async () => {
if (!response) {
response = await StrainApiCall()
}
return response
}
const StrainApiCall = () => {
return axios.get('yourdata.com') // your api call
}
export {
getData
}
I am working on a vue project where I am using vuex for managing state. I have defined state, actions, mutations as well as dispatch to call the action. But the problem is, I am getting an error near dispatch like Cannot read property 'getProduct'(action name) of undefined at Store._callee.
Can anyone guide me where I am doing wrong?
Here is my code:
Dispatch action from component:
async created() {
try {
await this.$store.dispatch("getProduct");
} catch (error) {
console.log("Error", error);
}
}
Actions code:
Here in ProductService, I have getProduct() function where I am performing API call.
const actions = {
async getProduct({ commit }) {
commit("GET_PRODUCT", await ProductService.getProduct());
}
}
Mutation code:
const mutations = {
GET_PRODUCT: (state, product) => {
state.product = product; // Here I am mutating the state
}
}
After debugging a long time, I got to know that there was an error in service function 'ProductService.getProduct()' inside action code. Here in my case I have created service file named 'ProductService' in which I have defined functions for API calls and 'getProduct()' is one of the functions where API call is done to get list of products.
While I tried to print whether this function call is returning values or not and this was returning undefined and for that the above error was coming. Then I fixed issue in service function for which this function call returns undefined and after that it works fine.
Error was in below line of code.
commit("GET_PRODUCT", await ProductService.getProduct());
Thanks #skirtle and #Radu Diță for your comments.