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

"Learn how to clear an input field using jQuery with this simple guide

I've gone through a few discussions, such as this one and that one, but I'm still struggling to clear the input field after submission. What is the simplest way to achieve this? This is my current approach: $(document).ready(function(){ $(& ...

Implementing a PHP button update functionality sans utilizing an HTML form

I need a way to update my database with just a click of a button, without using any forms or POST requests. Most examples I've seen involve updating through forms and the $_POST method. Is there a simpler way to update the database by directly click ...

How can I simulate keyboard events in Angular using a button click?

I've included separate buttons for Ctrl+z and Ctrl+y functionalities. When these buttons are clicked, I want them to perform the respective undo and redo actions programmatically. Below is the code snippet for this functionality. undoText(event:MouseE ...

Tips for implementing computed fields in the Syncfusion Vue.js data grid

Is there a way to utilize computed values in the Syncfusion Vue JS data grid? For instance Let's say I have 5 columns: QUANTITY, MRP, DISCOUNT, DISCOUNTED PRICE, TOTAL. I need to derive the DISCOUNTED PRICE from the provided values of MRP and DISCOU ...

Capture all URLs containing [...slug] and generate static props only for valid addresses in Next.js

I am utilizing dynamic routes with the fallback:true option to ensure newly created pages are accepted. First, I check if the parameters are true, then I create related props and display the component with those props. In the console, I can observe that Ne ...

Is there a way to set columns as initially hidden in MaterialTable?

I have a MaterialTable with many columns, and some of them are not always necessary to display. I am looking for a way to hide these columns unless the user specifically selects them. I attempted to use the hidden: true property in the column configuratio ...

What is the best way to change the status of a disabled bootstrap toggle switch?

I'm working with a read-only bootstrap toggle that is meant to show the current state of a system (either enabled or disabled). The goal is for it to update every time the getCall() function is called. However, even though the console logs the correct ...

Using jQuery to Activate Genuine Events

Is it true that jQuery's trigger() only executes event handlers bound with jQuery? I have some modules that utilize native browser event binding. Although the solution from works for me, I'm curious if there is a built-in way in jQuery to handle ...

Implementing Default Language in Next.js 14 for Static Export without URL Prefix: A Step-by-Step Guide

Currently, I am in the process of developing a website using Next.js 14, with the intention of exporting it as a static site for distribution through a CDN (Cloudflare Pages). The website I am working on requires support for internationalization (i18n) to ...

I need assistance with a feature on my website where a new form is added every time the invite button is clicked, and the form is deleted when the delete button is

Invite.js This invite component includes an invite button outside the form and a delete button inside the form. The goal is to delete the form when the delete button is clicked. I have utilized useState and sourced this form from material-ui. Can anyone ...

Comparing $.fn.fancybox and $.fancybox: What sets them apart?

I'd like to understand the distinction between the two items shown above. In what ways do they differ from each other? ...

The cascading menu causes interference with the function of other elements in the

I am currently designing a navigation bar that includes a drop-down menu (with plans to add another one in the future). The issue I'm facing is that when the user clicks on the drop-down menu, it shifts all of the navigation links to the right. What I ...

Generating a File that Imports Components and Instantly Exports Them Once More

Having trouble with this code. Initially, I had: // file 1 import Box from '@/components/Box' import Popup from '@/components/Popup' const MDXComponents = { Box, Popup } // using MDXComponents somewhere in file 1 Now, to manage t ...

The asyncData function in Nuxt is throwing a surprise setTimeout (nuxt/no-timing-in-fetch-data)

Having trouble running a code on my pages/posts/index.vue page where I keep getting an error message 'Unexpected setTimeout in asyncData'. Can anyone provide assistance in understanding this error and suggest if any additional plugins are needed? ...

Tips for preventing users from returning to the login page after they have already logged in using VueJS

How can I prevent users from navigating back to the login page after they have already logged in? Is there a way to achieve this using guards in routes? Here is the code: guard.js export default function guard(to, from, next) { const token = localSto ...

Nested checkbox table toggle/Select-Deselect

I have created a page that includes a nested table with checkboxes for selecting all the table cells <td>, as well as checkboxes for each individual table cell <td>. My goal is to: CheckAll checkbox should be able to check/uncheck all the pa ...

The G/L account specified in the SAP B1 Service Layer is invalid and cannot be used

I attempted to generate a fresh Incoming payment utilizing the service layer, but encountered this issue G/L account is not valid [PaymentAccounts.AccountCode][line: 1] Here is my JSON: { "DocType": "rAccount", "DueDate& ...

Uncovering the key based on the value in MongoDB

I'm currently working with Node.js using the express framework and Mongoose for MongoDB, and I've got a query regarding efficient data retrieval. Imagine having a mongo document structured like this: test : {a:1, b:2, c:2, d:1}; While it' ...

What is the best way to capture user input using an onClick event in JavaScript and then display it on the screen?

I'm in the process of upgrading a table, and while most of it is working fine, there is one function that's giving me trouble. I want this function to return an input with an inline onClick event. The actual return value is displaying correctly, ...

Securing API routes in Laravel

I have a Laravel application integrated with VUEJS for the front-end. I am retrieving data through API Routes. As an example, the route to fetch posts data is http://localhost/api/posts What would be the most effective method to secure my routes? After r ...