Home > OS >  How to fetch data from API in vuex
How to fetch data from API in vuex

Time:03-01

I want to use vuex to store some data fetched from the server that my SPA Vue app will need in different pages, this to avoid that a new ajax request is made every time that the user will change product page (it's an headless ecommerce).

My question is simple, how I can push the fetched data into an array that is defined in my store? How I will get the data in my components? I'm writing the code but not sure if I've done it well.

import { createStore } from 'vuex'
import axios from 'axios'

export default createStore({
  state: {
    products: []
  },
  mutations: {
    updateProductsData(state, products){
      // not sure how to proceed here
    }
  },
  actions: {
    fetchProducts(){
      const baseURL = 'https://www.example.com/app/index.php/wp-json/shop/v1/products';
      let productsData = [];
      axios.get(baseURL).then( response => {
        response.data.forEach( el => {    
          console.log(el);
          let details = {
            id: el.id,
            slug: el.slug,
            name: el.name,
            price: el.price,
            description: el.description,
            short_description: el.short_description
          }
          productsData.push(details);
        });
        store.commit('updateProductsData', productsData);
      }).catch( e => console.log(e) );
    }
  }
})

In my components where I need to load the data I have this code


export default {
  name: 'Home',
  data(){
    return {
      loaded: false,
      offers: [],      
    }
  },
  created(){

  }, 
  mounted(){
    this.$store.dispatch('fetchProducts').then( res => this.offers.push(res) )   
  },
}

CodePudding user response:

Inside your updateProductsData mutation use state.products = [...products] to add your loaded products to your state

Check https://www.vuemastery.com/courses/vuex-fundamentals/vuex4-intro-to-vuex for a short intro to Vuex

CodePudding user response:

Update your store action to return the products data array.

fetchProducts() {
  const baseURL = "https://www.example.com/app/index.php/wp-json/shop/v1/products";
  const productsData = [];

  axios
    .get(baseURL)
    .then(response => {
      response.data.forEach(el => {
        console.log(el);

        const details = {
          id: el.id,
          slug: el.slug,
          name: el.name,
          price: el.price,
          description: el.description,
          short_description: el.short_description
        };

        productsData.push(details);
      });
    })
    .catch(e => {
      console.log(e);
    });

  return productsData;
}

Now when you dispatch the action from your component, the results we be sent back.

Better Way

A better way to do this would simply be to return the Axios call itself which is a Promise, which you can await on in your component.

Alternatively, you can wrap the Axios call in your own Promise and resolve it with just the data, handling errors and objects in your component for better feedback to the user, as follows:

fetchProducts() {
  const baseURL = "https://www.example.com/app/index.php/wp-json/shop/v1/products";

  return new Promise((resolve, reject) => {
    axios
      .get(baseURL)
      .then(response => {
        resolve(response.data);
      })
      .catch(e => {
        reject(e);
      });
  });
}

Proper Way

To use the store properly, you should implement your VueX action like:

fetchProducts({ commit }) {
  const baseURL = "https://www.example.com/app/index.php/wp-json/shop/v1/products";

  return new Promise((resolve, reject) => {
    axios
      .get(baseURL)
      .then(response => {
        commit("setProductData", res.data);
      })
      .catch(e => {
        reject(e);
      });
  });
}

Add the following mutation:

setProductData(state, productData) {
  state.products = productData.map(product => {
    return {
      id: product.id,
      slug: product.slug,
      name: product.name,
      price: product.price,
      description: product.description,
      short_description: product.short_description
    };
  });
}

Update your component to be:

export default {
  name: "Home",
  data() {
    return {
      loaded: false,
      offers: []
    };
  },
  computed: {
    products() {
      return this.$store.state.products;
    }
  },
  mounted() {
    this.$store.dispatch("fetchProducts");
  }
};

CodePudding user response:

You can refer to the doc of Vuex about the use of actions and mutations https://vuex.vuejs.org/guide/actions.html . It's detailed...

As Vuex suggests, you should put async operations in actions (like fetching data from the server in your example). Then you should commit a "mutation" to use the fetched data to set your state like the code given below

import { createStore } from 'vuex'
import axios from 'axios'

export default createStore({
  state: {
    products: []
  },
  mutations: {
    updateProductsData(state, products){
      // here set your state
      state.products = products
    }
  },
  actions: {
    fetchProducts(){
      const baseURL = 'https://www.example.com/app/index.php/wp-json/shop/v1/products';
      let productsData = [];
      axios.get(baseURL).then( response => {
        response.data.forEach( el => {    
          console.log(el);
          let details = {
            id: el.id,
            slug: el.slug,
            name: el.name,
            price: el.price,
            description: el.description,
            short_description: el.short_description
          }
          productsData.push(details);
        });
        store.commit('updateProductsData', productsData);
      }).catch( e => console.log(e) );
    }
  }
})

If you want to use the state in your components, you can put it in computed attribute.

export default {
  name: 'Home',
  data(){
    return {
      loaded: false,
    }
  },
  computed:{
    // map this.offers to store.state.products
    offers(){
      return this.$store.state.products
    }
  },
  created(){

  }, 
  mounted(){
    // dispatch 'fetchProducts' to fetch data
    this.$store.dispatch('fetchProducts')
  },
}
  • Related