Mey be it is simple, but I'm new in frontend. I have a page component. And I need to fetch data before component calculated.
import {mapActions, mapGetters} from 'vuex'
export default {
name: "notFoundPage",
methods: {
...mapActions([
'GET_SUBCATEGORIES_FROM_CATEGORIES'
]),
},
computed: {
...mapGetters([
'SUBCATEGORIES'
]),
subCategories() {
// doing some calculations with already updated SUBCATEGORIES in store
}
return result;
}
},
created() {
this.GET_SUBCATEGORIES_FROM_CATEGORIES()
> **// from here we go to store**
},
mounted() {
this.GET_SUBCATEGORIES_FROM_CATEGORIES()
}
}
store:
let store = new Vuex.Store({
state: {
categories: [],
subcategories: []
},
mutations: {
SET_CATEGORIES_TO_STATE: (state, categories) => {
state.categories = categories;
},
SET_SUBCATEGORIES_TO_STATE: (state, subcategories) => {
state.subcategories = subcategories;
}
},
actions: {
GET_CATEGORIES_FROM_API({commit}) {
return axios('http://localhost:3000/categories',
{
method: "GET"
})
But here compiler returns to component. I do not have any idea, why it is not finishing this action. And after calculating the computed block in component it returns to this point. But I need 'SET_CATEGORIES_TO_STATE' already updated
.then((categories) => {
commit('SET_CATEGORIES_TO_STATE', categories.data)
return categories;
}).catch((error) => {
console.log(error);
return error;
})
},
GET_SUBCATEGORIES_FROM_CATEGORIES({commit}) {
this.dispatch('GET_CATEGORIES_FROM_API').then(categories => {
let subs = categories.data.map(function(category) {
return category.subcategories.map(function(subcategory) {
return subcategory.name
})
})
commit('SET_SUBCATEGORIES_TO_STATE', subs)
return subs
})
}
},
getters: {
CATEGORIES(state) {
return state.categories;
},
SUBCATEGORIES(state) {
return state.subcategories;
}
}
if you have difficulties with timings and async tasks, why don't you use async/await?
you want to wait in a async function (for example calling a backend for data) till the data is fetched. then you want to manipulate/delete/change/add, do what ever you want with that data and display the result on screen.
the point is, Vue is a reactive Framework, which means it rerenders (if the setup is correct made) the content by itself after what ever calculation is finished. so don't worry about something like that.
to be honest, the question is asked really weird. and your code is hard to read. sometimes moving two steps back and try a other way isn't false as well.
Related
Getter is returning empty value in observer. But the state is setting properly in the mutation.
Not able to check in Vuex dev tools in console as it says "No Store Detected". I've checked it by logging it in console
Vue File :
computed: {
...mapGetters('listings', ['listingContracts']),
},
methods: {
...mapActions('listings', [
'productBasedListings',
]),
},
onChange(product) {
this.productBasedListings( product.id );
console.log('LIST:', this.listingContracts); // Empty in observer
},
Store :
state: {
contracts: [],
},
getters: {
listingContracts(state) {
console.log('GETTER', state.contracts); // Empty in observer
return state.contracts;
},
},
mutations: {
setListing(state, { lists }) {
state.contracts = lists;
console.log('AFTER MUTATION:', state.contracts); // Setting the value properly
},
},
actions: {
async productBasedListings({ commit }, { id, state }) {
let listing = [];
try {
listing = await publicApi.listings(id);
console.log('ACTION:', listing);
commit({
lists: listing,
type: 'setListing',
});
} catch (e) {
console.error(`Failed to change #${id} state to #${state}:\t`, e);
throw e;
}
},
}
Here "Getter" does not have any values but "After Mutation" we have the values.
Because initially the store variable is empty.The values are itself set in the mutation.Hence showing up after mutation is called.
Well now to get data after mutation is fired use async await in your method as below:
async onChange(product) {
await this.productBasedListings( product.id ).then(() => {
console.log('LIST:', this.listingContracts);
})
},
I am fetching the data from a MongoDB through sending GET requests to my API. Then I loop through the response.data and in each response.data through its properties to push the data which I need to nextArray. And this nextArray should be passed to the schedulingQuality-state in the Vuex. That's how it looks like:
methods: {
...mapActions(
['setSchedulingQuality']
),
get_data() {
const nextArray = [];
for(let i in this.SelectedtValues) {
axios.get('http://127.0.0.1:5000/getexp/'+this.SelectedtValues[i])
.then(res => {
for(let n in res.data) {
nextArray.push(res.data[n].output)
}
}
)}
console.log(nextArray);
},
computed: {
...mapGetters(
['schedulingQuality','selectedValues']
),
SelectedtValues() {
return this.$store.getters.selectedValues;
} ,
schedulingQuality() {
return this.schedulingQuality;
}
}
When I'm printing out the nextArray then it seems to be ok. I'm getting a [] on the console and after I click on it the correct content appears with a small i icon which tells: "Value below was evaluated just now". However I am not able to print out the items of this Array separately, each of them has a value of undefined, when I try that.
But my main problem is that it throws an Maximum call stack size exceeded error, when I'm trying to pass it to my Vuex-state in the code above befor printing out, like:
this.setSchedulingQuality(nextArray)
Here is my Vuex-code:
import Vuex from "vuex";
import axios from "axios";
const createStore = () => {
return new Vuex.Store({
state: {
schedulingQuality: [],
},
mutations: {
SchedulingQuality(state, payload) {
state.schedulingQuality = payload;
}
},
actions: {
setSchedulingQuality({commit}, payload){
commit('SchedulingQuality',payload)
}
},
getters: {
schedulingQuality(state) {
return state.schedulingQuality;
}
}
});
};
export default createStore;
My questions are:
Why it is not possible to print out the Array items separately?
Why I'am getting this error
And how can I fix it?
Thank you for your time.
axios call is asynchronous. At the time you call console.log(nextArray), axios function is not finished yet. That's why you got empty array.
You call multiple api asynchronously, I suggest you check out Promise.all
get_data() {
const nextArray = [];
Promise.all(this.SelectedtValues.map(value => {
return axios.get('http://127.0.0.1:5000/getexp/' + value)
})).then(results => {
results.map(res => {
for(let n in res.data) {
nextArray.push(res.data[n].output)
}
})
console.log(nextArray);
}).catch(err => {
console.error(err)
})
}
I am creating an app and I have a component "Message" which uses a store to get data back from a JSON file (this will be eventually a database) and the component is as follows:
export default {
props: ['message'],
mounted: function() {
this.$store.dispatch("FETCHMESSAGE", this.message);
},
computed: {
title: function() {
return this.$store.state.message;
}
}
}
I have the following mutation:
FETCHMESSAGE: function (context, type)
{
var data = json.type; // Get the data depending on the type passed in
// COMMIT THE DATA INTO THE STORE
}
And I use it as the following:
<MessageApp message="welcome"></MessageApp>
This works for the most part and the correct message is displayed. The issue is when I have multiple instances of MessageApp being called on the same page. They both show the same message (of the last message) being called. E.g.
<MessageApp message="welcome"></MessageApp>
<MessageApp message="goodbye"></MessageApp>
They will each show the goodbye message. I know why this is happening but is it possible to have multiple instances of the store so that this does not happen?
Vuex is "a centralized store for all the components in an application," as the docs say.
So imagine that you have a variable (or many) which you can use and change from all your components.
Also when you want to get properties from state, it is recommended to use getters.
I can't understand what you want to do, but if you want, you can have multiple states, getters, mutations and actions and use them as modules in the store (read more). See below example from Vuex docs:
const moduleA = {
state: { title: '' },
mutations: { changeTitle(state, payload) { state.title = payload } },
actions: { changeTitle({commit}, payload) { commit('changeTitle', payload) } },
getters: { getTitle(state) { return state.title } }
}
const moduleB = {
state: { title: '' },
mutations: { changeTitle(state, payload) { state.title = payload } },
actions: { changeTitle({commit}, payload) { commit('changeTitle', payload) } },
getters: { getTitle(state) { return state.title } }
}
const store = new Vuex.Store({
modules: {
a: moduleA,
b: moduleB
}
})
store.state.a // -> `moduleA`'s state
store.state.b // -> `moduleB`'s state
How can i destroy this watcher? I need it only one time in my child component, when my async data has loaded from the parent component.
export default {
...
watch: {
data: function(){
this.sortBy();
},
},
...
}
gregor ;)
If you construct a watcher dynamically by calling vm.$watch function, it returns a function that may be called at a later point in time to disable (remove) that particular watcher.
Don't put the watcher statically in the component, as in your code, but do something like:
created() {
var unwatch = this.$watch(....)
// now the watcher is watching and you can disable it
// by calling unwatch() somewhere else;
// you can store the unwatch function to a variable in the data
// or whatever suits you best
}
More thorough explanation may be found from here: https://codingexplained.com/coding/front-end/vue-js/adding-removing-watchers-dynamically
Here is an example:
<script>
export default {
data() {
return {
employee: {
teams: []
},
employeeTeamsWatcher: null,
};
},
created() {
this.employeeTeamsWatcher = this.$watch('employee.teams', (newVal, oldVal) => {
this.setActiveTeamTabName();
});
},
methods: {
setActiveTeamTabName() {
if (this.employee.teams.length) {
// once you got your desired condition satisfied then unwatch by calling:
this.employeeTeamsWatcher();
}
},
},
};
</script>
If you are using vue2 using the composition-api plugin or vue3, you can use WatchStopHandle which is returned by watch e.g.:
const x = ref(0);
setInterval(() => {
x.value++;
}, 1000);
const unwatch = watch(
() => x.value,
() => {
console.log(x.value);
x.value++;
// stop watch:
if (x.value > 3) unwatch();
}
);
For this kind of stuff, you can investigate the type declaration of the API, which is very helpful, just hover the mouse on it, and it will show you a hint about what you can do:
I'm trying to pull an array from my api to a component using vuex but I'm at a loss and probably in over my head in attempting this. With the api being accessed directly from a component I had it set up like this and it was fine:
data () {
return {
catalog:[],
}
},
created() {
this.$http.get('https://example.net/api.json').then(data => {
this.catalog = data.body[0].threads;
})
}
For reference the json looks similar to this:
[{
"threads": [{
"no: 12345,
"comment": "comment here",
"name": "user"
}, {
"no: 67890,
"comment": "another comment here",
"name": "user2"
}],
//this goes on for about 15 objects more in the array
"page": 0
}]
When I move this all to store I'm losing grasp on how to actually make this work. I've used vuex before just never with vue-resource.
//store.js
state: {
catalog: []
},
actions: {
getCatalog({commit}){
Vue.http.get('https://example.net/api.json').then(response => {
commit('LOAD_CATALOG', response.data.data)
});
}
},
mutations: {
LOAD_CATALOG (state) {
state.catalog.push(state.catalog)
}
},
getters: {
catalog: state => state.catalog,
}
//component.vue
created () {
this.$store.dispatch('getCatalog')
},
computed: {
catalog () {
return this.$store.getters.catalog
}
}
I'm aware this is wrong and I'm getting max call stack size errors. How can I get the same results as posted in the example above (this.catalog = data.body[0].threads;) when I put everything in store?
Let me know if anything needs clarification! I'm still pretty new at using Vue 2.0.
Your main issue is with your mutation.
Mutations are synchronous updates to the state, therefore you are correctly calling it from the action (where you process your async request) but you aren't passing the mutation anything to place in the state. Mutations accept arguments, so your LOAD_CATALOG mutation would accept the catalogData, i.e.
mutations: {
LOAD_CATALOG (state, catalogData) {
state.catalog = catalogData
}
},
Also if you are using vue resource for Vue 2 then you should be passing the body of the response to the mutation, i.e.
getCatalog({commit}){
Vue.http.get('https://example.net/api.json').then(response => {
commit('LOAD_CATALOG', response.body[0].threads)
});
}
The next issue is you don't need the getter, getters allow us to compute a derived state, you don't need them just to return an existing state (in your case catalog). A basic example of where you may use a getter would be to add 1 to a counter stored in state, i.e.
getters: {
counterAdded: state => state.counter + 1,
}
Once you've made these changes things will look a bit more like below:
//store.js
state: {
catalog: []
},
actions: {
getCatalog({commit}){
Vue.http.get('https://example.net/api.json').then(response => {
commit('LOAD_CATALOG', response.body[0].threads)
});
}
},
mutations: {
LOAD_CATALOG (state, catalogData) {
state.catalog = catalogData
}
},
//component.vue
created () {
this.$store.dispatch('getCatalog')
},
computed: {
catalog () {
return this.$store.state.catalog
}
}