I am using Vue.js Options API. The problem is that when I try to provide data for other components after fetching from API, injecting doesn't work and i have no idea why. Maybe provide is executing too fast and therefore passing an empty array? I don't know, please help.
App.vue file:
<script>
// import { RouterLink, RouterView } from 'vue-router'
import TheHeader from './components/TheHeader.vue'
import Filters from './components/filters/Filters.vue'
import Countries from './components/Countries.vue'
export default {
data() {
return {
allCountries: []
}
},
components: {
TheHeader,
Filters,
Countries
},
methods: {
fetchCountries() {
fetch('countries.json')
.then((res) => {
if (res.ok) {
return res.json()
} else {
return Promise.reject(`Http error: ${res.status}`)
}
})
.then((res) => {
this.allCountries = res
})
.catch((error) => {
console.error(error)
})
}
},
created() {
this.fetchCountries()
},
provide() {
return {
allCountries: this.allCountries
}
}
}
</script>
<template>
<TheHeader />
<main class="px-8 pb-12 sm:px-16">
<Filters />
<Countries />
</main>
</template>
<style>
@import url('https://fonts.googleapis.com/css2?family=Nunito+Sans:wght@300;600;800&display=swap');
html {
font-family: 'Nunito Sans', sans-serif;
}
</style>
Countries.vue file:
<template>
<div id="country-wrapper" class="grid grid-cols-auto-fill justify-center gap-12 md:gap-20">
<CountryItem v-for="country in filteredCountries" :key="country.cca3" :country="country" />
</div>
</template>
<script>
import CountryItem from './CountryItem.vue'
export default {
inject: ['allCountries'],
data() {
return {
filteredCountries: this.allCountries
}
},
components: {
CountryItem
}
}
</script>
I tried with computed values, and rearranging the order in different ways, but it doesn't work
There's no way how allCountries
can be reactive this way, it's used by value in data
, before it's assigned to res
.
This is what ref pattern is for, it allows to use a reference instead of a value. It's unnecessary to use Vue ref
composition API for this purpose, a way it's supposed to work in any Vue version is to pass an object everywhere.
In a parent:
data() {
return {
allCountries: { value: [] }
}
},
provide() {
return {
allCountries: this.allCountries
}
},
methods: {
fetchCountries() {
...
this.allCountries.value = res
}
In a child:
inject: ['allCountries'],
computed: {
filteredCountries() { return this.allCountries.value }
}
Unless there may be different provided values with the same name across the application, this is the case for a global store.