async lifeCycles in Vue are a misleading syntax.
Every Vue lifecycle is only a trigger to run whatever code you put in there at that particular time.
But Vue doesn't wait for the promise to resolve and hold everything else (related to the component's lifecycle) until it happens. In effect, all you do is delay the execution of the code you place in the lifecycle until some promise resolves.
To give you a better understanding of what's going on, the following syntaxes are equivalent:
async created() {
const data = await fetchSomeData();
// rest of code depending on `data`
}
The equivalent:
created() {
fetchSomeData().then(data => {
// rest of code depending on `data`
});
}
Because async lifecycles are a misleading syntax, it's typically discouraged in applications developed by large teams, in favor of the .then() syntax. This is to avoid minor bugs created by misunderstanding when code actually runs. For example, if a new developer places some code into an async hook (without looking closely at the rest of the code in the hook), the code might run later than intended, unless placed before any await.
To fix whatever errors you're trying to fix, just wrap what can't be rendered until actual data has resolved into a if (inside component) or v-if (inside template).
Typical usage examples:
computed: {
someComputed() {
if (this.data.length) {
// returned when data has length
return something
}
// returned when data has no length
return somethingElse
}
}
or:
<div v-if="data.length">
<!-- markup depending on actual data... -->
</div>
<div v-else>
loading...
</div>
Note: the computed above will automatically react to the change in data's length (no need for a watch), because computed properties get re-run whenever their internal reactive references change values. As you'd expect, they recalculate/rerender anything depending on them. Same is true for <v-if>. Internally they both use what's known as Vue's "injections and reactivity".