Using Vue.js along with vuex and axios allows for data retrieval only upon the second load

After creating a Vue.js app with vuex as a central store and using axios for basic API calls, I implemented the following store action:

  loadConstituencyByAreaCodeAndParliament({commit}, {parliament_id, area_code}) {
    axios.get('/cc-api/area-code/' + parliament_id + '/' + area_code)
         .then((response) => {
           commit('SET_CONSTITUENCY', response.data);
         })
         .catch(function(error){
           commit('SET_CONSTITUENCY', null);
          }
         )
  }

In a single component file, I created a form for users to input an area code. This form triggers the above action to retrieve the constituency corresponding to the area code:

export default {
  name: 'AreaCodeForm',
  components: {
    PostalCodeInput
  },
  props: ['parliament_id'],
  data: () => ({
    postalCode: ''
  }),
  methods: {
    search_area_code(submitEvent) {
      let area_code = submitEvent.target.elements.area_code.value;
      let payload = {
        parliament_id: this.parliament_id,
        area_code
      }
      this.$store.dispatch('loadConstituencyByAreaCodeAndParliament', payload).
          then(() => {
        let constituency = this.$store.getters.getConstituency();
        // do some things with the data received from the API
        // but everything depending on constituency does not work the first time.
        // Data received from the API is here available only from the second time on
        // wehen this code run.
      })
    }
  }
}

Despite expecting the $store.dispatch method to return a promise and populate the constituency variable with fetched data, it remains empty initially. The issue resolves itself upon re-entering the area code. It appears that even with the use of promise.then, the data is not immediately stored in the store. Subsequent attempts yield the expected results.

Answer №1

According to a comment by user ABC, the solution involves returning the axios call:

  fetchConstituencyByParliamentAndArea({dispatch}, {parliament_id, area_code}) {
    return axios.get('/cc-api/area-code/' + parliament_id + '/' + area_code)
         .then((response) => {
           dispatch('SET_CONSTITUENCY', response.data);
         })
         .catch(function(error){
           dispatch('SET_CONSTITUENCY', null);
          }
         )
  }

Answer №2

Keep in mind the importance of utilizing the return statement when working on asynchronous tasks. There are two ways you can refactor your code, either sticking with promise or using async/await.

Option 1: async/await


async modifyConstituencyByAreaCodeAndParliament({ commit }, { parliament_id, area_code }) {
    try {
      const { data } = await axios('/cc-api/area-code/' + parliament_id + '/' + area_code)
      commit('SET_CONSTITUENCY', data)
      return data
    } catch (error) {
      commit('SET_CONSTITUENCY', null)
      return error
    }
  }

Key Points:

  • Make use of a return statement in both sections of the try/catch blocks.
  • The usage of .get in axios is not mandatory since it defaults to the get method.
  • You have the option to employ object Destructuring assignment with { data } by default with axios. The default good http responses retrieve data. A more advanced approach could be
    const { data: constituencyResponse } = await...
    , where you work with constituencyResponse and potentially save a few lines of code each time.

Option 2: Promise


First Approach: Handle everything within the store.

 // actions
modifyConstituencyByAreaCodeAndParliament({ commit, dispatch }, { parliament_id, area_code }) {
  axios('/cc-api/area-code/' + parliament_id + '/' + area_code)
    .then(({data}) => {
      commit('SET_CONSTITUENCY', data)
      dispatch('actionTwo', constituency)
    })
    .catch((error) => {
      console.log("error", error)
      commit('SET_CONSTITUENCY', null)
    })
}

actionTwo({commit}, constituency) {
  console.log("actionTwo", constituency)
  // perform some actions
  commit('COMMIT', 'Final value')
}
// Component
// Manage it with a computed property that references a getter or the store state.

{
  computed: {
    getConstituency(){
      return this.$store.state.constituency
    },
    getSomeOtherConstituency(){
      return this.$store.state.constituency.something / 3
    }
  },

  // Optionally, utilize a `watcher` to listen and react to changes.
  watch: {
    getConstituency(update) {
      // Executed every time getConstituency updates.
      // Ensure it has the same name.
      // Perform certain actions, where update represents the new value.
    }
  }
}

Second Approach: Manage data inside the component and then update the store.

Vue component example.

methods: {
 search_area_code(submitEvent) {
    const parliament_id = this.parliament_id
    const area_code = submitEvent.target.elements.area_code.value

    axios('/cc-api/area-code/' + parliament_id + '/' + area_code)
      .then(({data: constituency}) => {
          this.$store.commit('SET_CONSTITUENCY', constituency)
          // Work with constituency as needed inside the component.
        })
      .catch((error) => {
        console.log("error", error)
        this.$store.commit('SET_CONSTITUENCY', null)
      })
  }
},

Noteworthy Points:

The $store.dispatch method returns a promise. However, the constituency variable does not receive the data fetched with the loadConstituencyByAreaCodeAndParliament action and remains empty. Everything works well when entering the area code for a second time.

The issue may arise from mishandling the asynchronous code or attempting to implement a custom pattern. As mentioned earlier, incorporate store getters into computed properties.

Insights:

// Your action lacks a return statement, ensure to `return axios.get` within it.
this.$store.dispatch('loadConstituencyByAreaCodeAndParliament', payload).then(() => {
  let constituency = this.$store.getters.getConstituency()
})

// Without the `return` statement, the above code can be translated as
this.$store.dispatch('loadConstituencyByAreaCodeAndParliament', payload)
let constituency = this.$store.getters.getConstituency()

// Async alternative:
async doSomething(){
  await this.$store.dispatch('loadConstituencyByAreaCodeAndParliament', payload)
  let constituency = this.$store.getters.getConstituency()
}

// If updates are not reflecting, consider using `$nextTick` https://vuejs.org/v2/api/

this.$nextTick(() => {
  this.data = this.$store.getters.getConstituency()     
})

I trust this information proves beneficial to you.

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

Tips on defining the specific CSS and JavaScript code to include in your Flask application

I am currently working on a web application using Flask and I need to specify which CSS and JS files should be included in the rendered HTML page based on a condition. There are times when I want to include mycss1.css and myjs1.js: <link href="/sta ...

Python script using selenium webdriver to interact with an accordion container and expand its contents (round

After successfully creating a scraper, I encountered an issue where the data I needed to scrape was hidden and required manual expansion before scraping. Upon inspecting the webpage source code, I found that the data was located within 3 different accordio ...

Unable to establish connection with NodeJS Express Server

I'm having trouble connecting to my Express server. I've set up my Axios connection to the front end, but it doesn't seem to be reaching the endpoint. Even when I try to connect directly from the browser, it just keeps spinning. The server d ...

The Nextjs Image was preloaded using link preload, but it remained unused after a short period following the window's load event

I've encountered an issue while working with Next.js, a React-based framework. I am attempting to display the logo.png image using the Image component provided by Next.js. My image is stored in this folder: public/img Here is the code I'm using ...

Unveiling the Mystery: Uncovering the Selected Item in Ionic Checkboxes

I am trying to implement a feature in Ionic checkboxes where I can get the selected item when a user checks one or more checkboxes. Specifically, I want to identify which books the user has selected. Below are snippets of my code: <ion-item ng ...

Countdown malfunction: wrong date displayed

Utilizing the Countdownjs library in my project is resulting in an incorrect day count. Incorporating AngularJS, here is the custom directive I've implemented for the countdown: .directive('tempoPercorrido', function($interval){ ret ...

Display a 404 page on Vue router when the ID does not match

When it comes to displaying a 404 page if a parameter doesn't match, I'm a bit puzzled. For instance, if the user name is “joe” and someone tries to access “/joe/categories”, then the categories component should be displayed. Now, I want ...

Separate the iframe sessions

I am working with 6 iframes from the same domain but with different URLs and subdirectories. Each iframe sets a cookie with the same name but a different value using the HTML header "set-cookie". To prevent interference between these cookies, I need to fin ...

Trimming whitespace from strings within HTML tag attributes can be achieved using various methods

I have been reviewing the .cshtml pages of a website with the aim of adding ID attributes to various divisions and elements for testing purposes. These pages utilize AngularJS, and many of the elements I need to add ID attributes to are part of a list tha ...

Having trouble getting the express router to function properly in your Node.js TypeScript project?

One of the components in this application is registerClass, where all routes are added. The source code is in the dist directory since this node app is using TypeScript. However, when calling the http://localhost:9001/user endpoint, it seems that it is not ...

Using Vue.js to trigger mouseover or hover events within Element UI tabs

I need to display a tooltip when hovering over a tab in Vue.js. My tabs are functioning correctly, but I'm not sure how to implement a mouseover event on el-tab-pane? <el-tabs v-model="editableTabsValue" type="card" editable @edit="handleTabsEdit ...

Discover the method of extracting parameters from an event in Vuetify Vue.js

I am currently delving into the world of Vuetify and Vue.js, and I have a question regarding retrieving parameters when clicking on my treeview: For example, in the Chrome console with the Vue extension installed, I see: vue event update:active This pro ...

Analyzing the current time against a user-inputted time using Javascript

Looking at this html and javascript code, the goal is to compare an input time with the current time. If the input time is less than 2 hours, "Less time" should be displayed in the label; if it's more than 2 hours, then "sufficient time" should appear ...

Whenever I find myself being redirected to the login page, my goal is to eliminate the bottomTab from view

I'm looking to eliminate the bottom tab when I land on the login page, even though I've set it up for all pages. However, whenever I click on the login button, the tab remains visible. Here is my current code: import React, { useContext } from & ...

displaying a PDF file in Safari

Is there a way to display a PDF document within an HTML page without encountering a missing plugin error? I attempted to use the following code, but the error persists. Interestingly, if I drag the same PDF file directly into my browser, it displays perfe ...

Add an asterisk before each line of comment when working in a TypeScript file using the VS Code IDE

Within my VS Code workspace, I am using the Typescript language and would like to format my comments across multiple lines with a specific style (look out for the star character) /** *@desc any text * any text */ However, when I attempt to write a comm ...

Filtering deeply nested arrays

Hey, I'm working with this interesting array: [ { "Navn": "Long Island Iced Tea", "Nummer": "2", "Glas i ml": "250", "Instruktioner": "", "a": "Hæld is i glasset", "b": "pynt med en skive lime", ...

The Angular model does not automatically refresh when the Space or Enter key is pressed

Having an issue with my editable div and the ng-trim attribute. Even though I have set ng-trim to false, pressing SPACE or ENTER does not increment the string length by one in the div below. Using Angular 1.3.x and wondering if anyone has any ideas on how ...

display data labels within the chart - utilizing the power of angular.js in conjunction with chart.js

My goal is to display the chart's information without requiring the user to hover over any part of the chart. I am utilizing Chart.js with Angular.js I have the same question as this one posted here: question here! html code: <div class="wrapper ...

Interactive section for user input

I am looking to add a commenting feature to my website that allows for dynamic editing. Essentially, I want users to be able to click on an "Edit" span next to a comment and have it transform into an editable textarea. Once the user makes their changes and ...