CodeConnoisseur
CodeConnoisseur

Reputation: 1869

Provide Inject not working properly in vue 3 composition API

I am working with Vue 3 composition api and am retrieving weather data via async/await fetch and I get a 200 response and the data in the request within the Chrome Dev Tools.

In the component receiving the data and making the call I have a provide method and then I am injecting the data into another output component. The issue is in the inject component. The value for the injected variable is always null and does not update in the Vue Dev Tools so my data is never output to the screen. I went through the docs and the code is pretty much the same but I can't get it to work. Can anyone see an obvious issue?

Receiving Component

setup () {
    async function getCurrentWeather () {
      const response = await fetch(`${baseWeatherApiUrl}q=${userInput.value}`);

      userInput.value = null;

      return weatherData.value = await response.json();
    }

    const returnedWeatherData = reactive(weatherData);

    provide('returnedWeatherData', returnedWeatherData);

    return {
      getCurrentWeather,
      userInput,
      weatherData
    }
  }

output component

setup () {
    //Provide default of empty object in case no results exist
    const weatherData = inject('returnedWeatherData');

    console.log(weatherData) //No output even when making a new request to the weather api
    
    return {
      weatherData
    }
  }

As a separate test I tried to provide/inject hardcoded values found in the docs but still geolocation when injected remains null.

provide('geolocation', {
      longitude: 90,
      latitude: 135
    })
const userGeolocation = inject('geolocation')


    console.log(userGeolocation) // Nothing logged

    return {
      weatherData,
      userGeolocation
    }

Upvotes: 5

Views: 19619

Answers (2)

entio
entio

Reputation: 4263

In my case it was importing inject from "@vue/runtime-core" instead of "vue".

Of course provide was imported from "vue".

Just leaving here, maybe it's gonna save someone an hour.

Upvotes: 5

tony19
tony19

Reputation: 138276

The provide-ed argument should be the ref itself (not wrapped in a reactive()):

// Parent.vue
export default {
  setup () {
    const weatherData = ref()

    // ❌
    // const returnedWeatherData = reactive(weatherData);
    // provide('returnedWeatherData', returnedWeatherData);

    // ✅
    provide('returnedWeatherData', weatherData);
  }
}

And the child component's console.log() in setup() does not automatically get invoked again. You should wrap that call with watchEffect() so that it does get called upon change to the ref:

// Child.vue
import { inject, watchEffect } from 'vue'

export default {
  setup () {
    const weatherData = inject('returnedWeatherData')

    // ❌
    //console.log('new weatherData', weatherData.value)

    // ✅
    watchEffect(() => {
      console.log('new weatherData', weatherData.value)
    })
  }
}

demo

Upvotes: 8

Related Questions