Calling components may result in a race condition

I have integrated 2 components into my "App" that work together seamlessly. The first component is responsible for resolving the external IP address to a geographical location by making 2 axios.get calls and then passing them back to App.vue using emit.

Following this, I call upon "Weather" to retrieve the latitude/longitude data from the previous calls and fetch relevant weather information from the darksky API based on that location. However, I am encountering a race condition issue where sometimes, due to latency (about 50-60% of the time), I end up sending 0/0 coordinates to Weather, which are what I initialize as default values in App.vue. I am seeking ways to improve the reliability of the following code execution.

Here's the template structure in App.vue

<template>
  <div id="app">
        <img alt="Vue logo" src="./assets/logo.png">
    <ip @response="onResponse" /> // Requires completion before proceeding (includes axios calls)
    <Weather msg="The weather for:" :lat="lat" :long="long" :ip="ip" :city="city" :country="country"/>
  </div>
</template>

<script>
import Weather from './components/Weather.vue'
import ip from './components/ip_resolve.vue'

export default {
  name: 'App',
  data() {
    return {
      lat: 0,
      long: 0,
      ip: 0,
      country: 0,
      city: 0 
    }
  },
  components: {
    Weather,
    ip
  },

  //Listen for emitted values from ip_resolve - ensure data is updated before Weather runs
  methods: {
    onResponse(event) {
      this.lat = event.lat
      this.long = event.long
      this.ip = event.ip
      this.country = event.country
      this.city = event.city
    }
  }
}
</script>

ip_resolve.vue Component:

<template>
  <div class="Hemlo">

  </div>
</template>

<script>
const axios = require('axios').default;
const ipRegex = /ip=(\d{1,3}.\d{1,3}.\d{1,3}.\d{1,3})$/gmi
export default {
  name: 'ip',
  props:{
      ip: String,
      country: String,
      City: String,
      lat: Number,
      long: Number
  },
  mounted () {
    axios.get('https://www.cloudflare.com/cdn-cgi/trace')
    .then(response => (
        this.ip = ipRegex.exec(response.data)[1]
    )
        .then(
            axios.get('https://cors-anywhere.herokuapp.com/http://api.ipstack.com/'+this.ip+'?access_key=<key>')
            .then( response => (
                    this.lat = response.data.latitude,
                    this.long = response.data.longitude,
                    this.country = response.data.country_name,
                    this.city = response.data.city
                ).then(
                    this.$emit('response', {
                        ip: this.ip,
                        lat: this.lat,
                        long: this.long,
                        country: this.country,
                        city: this.city
                    })
                )
            )
        )
    )
  }
}
</script>

Weather.vue Component:

<template>
  <div class="Hi">
    <h1>{{msg}} {{city}}, {{country}}</h1>
    <h2>Temp: {{ temp }}f</h2>
    <h2>Conditions: {{ conditions }}</h2>
  </div>
</template>

<script>

const axios = require('axios').default;
export default {
  name: 'Weather',
  props: {
    msg: String,
    resp: String,
    ip: String,
    lat: Number,
    long: Number,
    city: String,
    country: String,
    temp: String,
    conditions: String
  },
  mounted () {
    axios
      .get('https://cors-anywhere.herokuapp.com/https://api.darksky.net/forecast/<key>/'+this.lat+','+this.long)
      .then(response => (
        this.resp = response.data,
        this.temp = response.data.currently.temperature,
        this.conditions = response.data.currently.summary
      ))
  }

}
</script>

Answer №1

To maintain a clean data flow for components, it is recommended to segregate model logic into its own module using tools like vuex.

However, if you're looking for a quick fix in this scenario, you can simply add a v-if="responseReady" directive to the <Weather> component in App.vue. This ensures that the component is only mounted once the necessary data is retrieved. Additionally, you will need to create a boolean flag for the new prop in the data and onResponse methods. While this solution may not be the most elegant, it gets the job done swiftly.

  <Weather v-if="responseReady"  msg="The weather for:" :lat="lat" :long="long" :ip="ip" :city="city" :country="country"/>
...
  data() {
    return {
        lat: 0,
        long: 0,
        ip: 0,
        country: 0,
        city: 0,
        responseReady: false
      }
    }, 
...
    onResponse(event) {
      this.lat = event.lat
      this.long = event.long
      this.ip = event.ip
      this.country = event.country
      this.city = event.city
      this.responseReady = true;
    }

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

What is the best way to insert CSS code into a custom Vue directive file?

I need a solution that applies a gradient background to the parent div in case an image fails to load. I've attempted to create a directive for this purpose: export default { bind(el: any, binding: any) { try { ..... ...

Is it necessary for TypeScript classes that are intended for use by other classes to be explicitly exported and imported?

Is it necessary to explicitly export and import all classes intended for use by other classes? After upgrading my project from Angular 8 to Angular 10, I encountered errors that were not present before. These issues may be attributed to poor design or a m ...

Trouble accessing onclick function

My dataSend AJAX function is not being called when I use the onclick event. I have checked in the Inspector of my browser and confirmed that the click handler is attached to it. However, when I set a breakpoint in the function using the Debugger, it never ...

What could be causing the data filter function to return nothing?

Whenever I press the messageIncompleted button, everything works fine. But when I click on the messageCompleted button, the data suddenly disappears. Any ideas on how to tackle this issue? messageIncompleted() { this.messages = this.messages.filter(m ...

Can you please provide a detailed list of all the events that are compatible with the updateOn feature in Angular's ngModelOptions?

The reference documentation notes the following: updateOn: a string that specifies which event should be bound to the input. Multiple events can be set using a space delimited list. There is also a special 'default' event that aligns with the ...

What could be causing the JQuery date picker to fail to load on the initial ng-click event?

I am encountering an issue with a JQuery UI date picker that is loaded through ng-click using the code below: Input: <input type="text" id="datepicker" autocomplete="off" ng-model="selectedDate" ng-click="showDatepicker()" placeholder="(Click to sele ...

I attempted various methods but was unable to successfully call the webmethod in the code behind using jQuery Ajax and Knockout

I have attempted various solutions, such as enabling friendly URL resolution and utilizing web method with session enabled, but unfortunately, the issue remains unresolved. I kindly request your assistance in resolving this matter. Here is my HTML code for ...

Is there a way for me to adjust the typography background based on its current status?

Is there a way to dynamically adjust the background color of text based on the status value? Currently, when the status is pending, the background color defaults to yellow. For example, if the status changes to complete, I want the background color to ch ...

How can we efficiently generate ReactJS Router for Links and seamlessly display a unique page for each Link?

Currently, I have an array of objects named titleUrl, which contains titles and URLs retrieved from an API. To display these as links on the sidebar, I am utilizing a custom component called MenuLink. The links are generated by iterating over the keys in t ...

Switch classes according to scrolling levels

My webpage consists of multiple sections, each occupying the full height and width of the screen and containing an image. As visitors scroll through the page, the image in the current section comes into view while the image in the previous section disappe ...

Can anyone provide guidance on locating the parent of a pseudo element with Selenium WebDriver?

Is there a way to retrieve the parent web element of a pseudo element (if we can call it the parent) using JavaScript? I know that Selenium's methods for searching for web elements are not suitable for pseudo elements, but JavaScript does allow manipu ...

The style was not applied from because it has a MIME type of 'text/html', which is not a supported stylesheet MIME type, and strict MIME checking is turned on

I'm currently working on creating a Google web app that relies on a Google sheet in the backend. I prefer to develop locally in VSCode since the editor in Google Apps Scripts is quite limited. Additionally, I aim to incorporate Vue3 into my project. ...

What is the best way to retrieve an ng-model parameter within a controller?

I'm working on implementing a PUT method in my controller and need to bind the new value back to it. I've tried: <div ng-app="myApp" ng-controller="personCtrl"> <form> First Name: <input type="text" ng-mod ...

Having trouble creating a report with an HTML screenshot using Protractor

Need assistance with generating reports using a html screenshot in Protractor. I have followed all the necessary steps but encountered an error. Any help would be appreciated. Here is my conf.js: // Sample configuration file. var HtmlReporter = require(& ...

The issue of resolving NestJs ParseEnumPipe

I'm currently using the NestJs framework (which I absolutely adore) and I need to validate incoming data against an Enum in Typscript. Here's what I have: enum ProductAction { PURCHASE = 'PURCHASE', } @Patch('products/:uuid&apos ...

Adjustable div height: reduce until reaching a certain point and then begin expanding once more

Incorporating a hero section to display content is my current approach. The design adapts responsively utilizing the padding-bottom percentage strategy, along with an inner container that is absolutely positioned for central alignment of the content. The ...

Utilizing a functional component to incorporate a "load more" button in ReactJS

Hey everyone, I've come across this ReactJS code that I need some help with: function DisplaySolutions({solutions}) { const topSolutions = solutions.slice(0, 4); const remainingSolutions = solutions.slice(4); const [isD ...

Adding Bootstrap to container-specific styling in SCSS

I am currently in the process of upgrading to the most recent version of reactstrap & Bootstrap. Previously, I had reactstrap in my package.json file and downloaded Bootstrap SCSS in my client/src/styles/bootstrap directory. Now, my updated package.json c ...

How can I prevent Heroku from automatically running the script with 'npm start'?

I am currently in the process of developing a server-based application that utilizes automated scripts, also known as "bots," within a cloud environment. I have set up Heroku Scheduler to execute one of these scripts automatically, as illustrated in Figure ...

Learn how to incorporate an input field into a form using the same class name

I am facing a challenging JavaScript issue that I have been struggling to resolve. My predicament involves a dynamically formed table with form fields. Here is the code snippet in question: var table = document.getElementById("table"); var row = table. ...