Reputation: 18402
Here's my child's component async method:
async created () {
this.$parent.$emit('loader', true)
await this.fetchData()
this.$parent.$emit('loader', false)
}
fetchData
does an axios get call, to fetch data from API. However in a vue-devtools (events tab) i can only see the events, after i change the code and it hot reloads. Also i've set up console.log()
in a parent component:
mounted() {
this.$on('loader', (value) => {
console.log(value)
})
}
And i can see only false
in a console. My purpose is to emit loader set to true (so i can show the loader), then set it to false, when data is fetched.
My fetchData method:
import http from '@/http'
fetchData() {
return http.getOffers().then((resp) => {
this.offersData = resp.data
})
}
Contents of http.js:
import axios from 'axios'
import config from '@/config'
const HTTP = axios.create({
baseURL: config.API_URL
})
export default {
/* calculator */
getOffers() {
return HTTP.get('/url')
}
}
If i directly use return axios.get()
in async created()
, then it works. Problem is in this imported http instance.
Final solution
One of the problems was using different lifecycles, thanks to Evan for mentioning this.
Another problem was with async / await usage, changes to a fetchData()
method:
import http from '@/http'
async fetchData() {
await http.getOffers().then((resp) => {
this.offersData = resp.data
})
}
I had to make this method async and use await on axios request, since await is thenable, it does work. Also i've spotted an issue in https.js:
export default {
/* calculator */
getOffers() {
return HTTP.get('/url')
}
}
It returns HTTP.get()
, not a promise itself, i could have used then
here, and it would work, but, for flexibility purposes i didn't do that.
But, still, i don't get why it didn't work:
fetchData() {
return http.getOffers().then((resp) => {
this.offersData = resp.data
})
}
Isn't it already returning a promise, since it's chained with then... So confusing.
Retested again, seems like return
is working, lol.
Upvotes: 3
Views: 9566
Reputation: 4175
The issue here is that created
on the child component is getting called before mounted
on the parent component, so you're beginning to listen after you've already started your Axios call.
The created lifecycle event method does not do anything with a returned promise, so your method returns right after you begin the Axios call and the rest of the vue component lifecycle continues.
You should be able to change your parent observation to the created
event to make this work:
created() {
this.$on('loader', (value) => {
console.log(value)
})
}
If for some reason you need to do something that can't be accessed in created
, such as accessing $el
, I'd suggest moving both to the mounted
lifecycle hook.
Upvotes: 4
Reputation: 1095
I'd simply suggest restructuring your method, as there isn't really a need to make an async method since axios itself is asnychronus.
If you already have the fetchData method defined, and the goal is to toggle the loader state when a call is being made, something like this should do.
fetchData () {
this.$parent.$emit("loader", true)
axios.get(url)
.then(resp => {
this.data = resp
this.$parent.$emit("loader", false)
})
}
Of course these then statements could be combined into one, but it's the same idea.
Edit: (using the parent emit function)
fetchData () {
this.loader = true
axios.get(url)
.then(resp => this.data = resp)
.then(() => this.loader = false)
}
Upvotes: 2
Reputation: 4406
If what you are trying to achieve is to tell the direct parent that it's no longer loading, you would have to emit to the same instance like so
async created () {
this.$emit('loader', true)
await this.fetchData()
this.$emit('loader', false)
}
By removing the$parent
, you will emit from the current component.
--Root
--My-page.vue
-Some-child.vue
Now you will emit from some-child.vue
to my-page.vue
. I have not tried, but theoretically what you are doing by emiting via parent: (this.$parent.$emit('loader', false)
) You are emitting from my-page.vue
to root
.
So If you have a $on
or @loader
on the component like so: <Some-child @loader="doSomething"/>
, This will never run due to you emitting from the parent.
Upvotes: 1