I am trying to use Vuex and am having trouble to understand why my data is not the expected value.
What I am trying to do is pass the result of a getter to a mutation commit as follows
// TEST PRINT: return value of getter
console.log(this.$store.getters.reservationsCurrentWeek);
switch (this.activeCalendar) {
case 'week':
// Commit with getter result
this.$store.commit('setShownReservations', this.$store.getters.reservationsCurrentWeek);
break;
The first print shows the expected result.
However when I print what value is actually passed inside the mutation as follows:
// TEST PRINT: return value of getter
console.log(this.getters.reservationsCurrentWeek);
// TEST PRINT: parameter passed to the mutation.
console.log(value);
state.shownReservations = value;
The parameter value is is not what the getter returned (but some old value). When I access the getter directly in my mutation it also gives a correct value. I don't get why I can't pass the result of the the getter as a parameter to a mutation commit and why it produces an unreliable value?
From where are you trying to access this.getters.reservationsCurrentWeek ? If you are accessing getters from mutation and getters and mutations placed in one file you can use
mutations: {
YOUR_MUTATION(state, {data, getters}) {
console.log(getters);
}
}
and then access getters. Or import getters from another file if it placed in separate file.
Related
I've used MobX for a few years now, and love it, but sometimes my trace calls are not functioning, and I don't understand why not. There must be some fundamental thing that I've completely misunderstood, but most likely have been lucky enough to get through anyway. Here's an example of using trace() where I'm getting an error:
import { computed, observable, trace } from "mobx";
class Stat {
#observable baseValue = 1;
#computed get value() {
trace();
return this.baseValue;
}
}
const strength = new Stat();
strength.baseValue = strength.baseValue + 1;
The expected output, in my mind, is that trace reacts to the change in "baseValue" and logs the change. Instead, I'm getting the following error:
Error: [MobX] 'trace(break?)' can only be used inside a tracked computed value or a Reaction. Consider passing in the computed value or reaction explicitly
"Inside a tracked computed value" is, to my understanding, exactly what I'm doing. Or..?
Full sandbox: https://codesandbox.io/s/mobx-trace-trouble-ki2qj?file=/index.ts:0-312
As far as I understand this phrase
inside a tracked computed value or a Reaction.
you need to access computed value inside reactive context, like inside observer or reaction or autorun. Otherwise trace just don't have information about what is going on because your computed value is untracked at that moment by any observer.
So this will work:
const MyComponent = observer(() => {
return <div>{strength.value}</name>
})
or this
autorun(() => {
console.log(strength.value);
});
I have a variable defined in data
data() {
return {
pie_graph_data:[],
}
}
and this variable is not being anywhere. After getting response from server
let response = resp.data.success.pie_graph_data;
console.log(response);//this is array
console.log(this.pie_graph_data);//this is also an array
this.pie_graph_data = response;
console.log(response, this.pie_graph_data); //both become observer
I need to know if this.pie_graph_data is not used anywhere why its turning to observer
and more importantly How do I use this variable in template as array.
Logging pie_graph_data made you believe that it is just a plain empty array but actually it is not. If you can not see your arrays properties in your browsers console, you can log your empty arrays pie_graph_data.__ob__ property and you will see it is already an Observer. Arrays are iterable object and assigning additional properties doesn't make them lose their ability to be iterated over them. So there must be an other reason why chartjs is not working for you.
The issue was in child component where computed property was using the observer being passed by props.
Converting the computed property into method(getChartData) and calling it in watcher solved the issue for me.
watch:{
graphData(val){
if(val && val.length){
this.renderChart(this.getChartData(val),this.chartOptions);
}
}
},
I have the below code in my computed property. The function is expected to get way complicated. Is it correct to have it all here? I would like to have it in my store file, but I'm not able to call a function by name from within the computed property. Any advice ?
computed: {
assignValue() {
this.valueToSet = this.value1;
if (this.valueToSet < 10) {
return "1 week"
} else if (this.valueToSet < 20) {
return "2 weeks"
} else if (this.valueToSet < 30) {
return "3 weeks"
} else {
return 0;
}
}
}
To summarize, I would like to have it in my store.js (vuex), but how can I call/trigger a function by name inside "the computer property".
If it is not possible, any effective alternative? Or I should continue this way?
Vuex itself has getter properties that you can use with Vue component's computed property as shown in the docs.
As far as your code is concerned, there is no problem with your current approach. You should move this code to Vuex getter when you need to re-use that state in multiple components.
The only problem in your code is this.valueToSet = this.value1;. Computed properties should not produce a side-effect (including assignment). There is no direct harm, but it can have unintended consequences internally as computed values are cached. If you still need this part - this.valueToSet = this.value1; - move it to other computed property or use watch expression.
For example, I use a Getter for write a logic about a if object has a especify content.
const state = {
object = []
}
const getters = {
CHECK_OBJECT_STATE: (state) => {
if(Object.prototype.hasOwnProperty.call(state.object, "error")){
//return a message, in this case is not necessary proceed the logic.
}else{
//otherwise I need take state.object.id and fetch a new a action.
//CALL ACTION FETCH_OBJECT_ID
}
}
}
const actions = {
FETCH_OBJECT(...){
//SET MUTATION HERE
}
FETCH_OBJECT_ID (..) {..}
}
anyone can suggest me other method to do it, if it's not valid?
Vuex Getters are not designed for asynchronous tasks, those should be handled in the actions. I really think that getters operate best as pure functions which perform read-only operations on an existing state, so it should do only one job: retrieve the data in the state.
So you process the logic, the if statement in the actions, store the returned value in a state array object (which is pretty weird for me to name an array "object"), and the getter only has to retrieve such array. Things are reactive so that getter will always hold the latest data set.
I have a problem with iterating over mapGetters results.
My code looks like :
...mapGetters({
'shop' : 'getShops'
})
After that, when I iterate over the shops and change anything, it changes my parameters in state and it has impact on all of my app state. I need to change parameters on 'copy' of this getters but it also should be observable.
I've tried to assign mapGetters result to a computed variable but it also updated state
How can I achieve this?
here is a typical store getter:
const state = {
obj: {count:1}
}
const getters = {
obj: (state) => {
return state.obj
}
}
if you call a store by either mapGetters or directly through $store.state.obj, you are getting the object itself passed. The object javascritp provides is not immutable, and the nature of objects in js is such that if you make a change to the object when it's passed to a component, it will update in the store too.
There are two ways you can prevent objects not updating through the passed getter.
do not make changes to it EVER, just reference or copy values as needed when changes are needed.
return a copy of the object in the getter
I've personally only used approach 1, but if you need to return a copy for changing (2), you can use any one of these to create a copy
using ES6 spread operator (not a deep copy)
objCopy: (state) => {
return {...state.obj};
}
also a good option for ES6 (not a deep copy):
objCopy: (state) => {
return Object.assign({}, state.obj});
}
or the ES5 way, which creates a deep copy (so the children, grandchildren, etc don't succumb to same issue)
objCopy: (state) => {
return JSON.parse(JSON.stringify(state.obj));
}