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')
},
}