Vue effectively using computed property - vue.js

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.

Related

mobx computed always update that computed doesn't work

import {makeAutoObservable} from "mobx";
class Test {
id = 0
constructor() {
makeAutoObservable(this)
}
get total() {
console.log('enss')
return 2;
}
}
const store = new Test();
export default store;
call:
import {isComputed, isComputedProp} from "mobx";
console.log(isComputedProp(Test, 'total'),Test.total,Test.total, Test.total, isComputedProp(Test, 'total'))
console output:
enss
enss
enss
true 2 2 2 true
the computed did not work and does not serve as a cache.
i using mobx 6.6 version in react 18.
Thank you very much for your answer!
This is explained in the docs here
It sometimes confuses people new to MobX, perhaps used to a library like Reselect, that if you create a computed property but don't use it anywhere in a reaction, it is not memoized and appears to be recomputed more often than necessary. For example, if we extended the above example with calling console.log(order.total) twice, after we called stop(), the value would be recomputed twice.
Basically it won't be cached if you use it outside of reactive context.
You can use computed({ keepAlive: true }) option to change this behaviour

trace() error "can only be used inside a tracked computed value or a Reaction" when used inside computed

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);
});

Why does vue array become observer?

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

Unreliable data Vuex

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.

LESS: Change on-the-fly passed parameter through Mixin call

I have a LESS Mixin called in different stylesheets (i.e. one for each breakpoint controlled by media queries). In each stylesheet it is called with different parameter value such as:
"mobile.less":
.mixin(1);
"tablet.less":
.mixin(2);
.....
The mixin is defined (for example) as:
.mixin(#parameter) when (#parameter = 1)
{
body
{
font-style:italic;
}
.......
}
.mixin(#parameter) when (#parameter = 2)
{
.......
}
I'm developing a demo website so I wish that users could change this values on-the-fly changing value that is passed as parameter using a form field.
I tried the following method:
less.modifyVars({'#parameter' : <value from form field>});
But it would work only if #parameter is a "global" variable, not a passed parameter through the call...... Is there a method to change also passed parameters?
Thank you.
Original Answer
Yes, just make the variable outside the scope of the mixins but still use it in the guard expression. Something like:
#parameter: 1;
.mixin() when (#parameter = 1) {
body {
font-style:italic;
}
}
.mixin() when (#parameter = 2) {
body {
font-style:normal;
}
}
.mixin();
This generates the 1 code. If the variable gets set to 2, it generates the 2 code, etc.
Discussion of "re-process on the fly called mixins"
With reference to your comment, to my knowledge there is no way to directly re-process the local variable of a mixin call without doing something to the mixin definition itself to allow for it. So in your example, if "mobile.less" has a .mixin(1); call, how can you reprocess it to be, say, .mixin(4) based on user input. If you have not set up the call with a variable to begin with, then there is not way to "modify" the 1 in the original call. However, setting up with a variable call to begin with is really just a longer version of the answer I give above. Consider that this code essentially does the same as the above, only with more coding involved:
LESS Mixins Defined
.mixin(#parameter) when (#parameter = 1) {
body {
font-style:italic;
}
}
.mixin(#parameter) when (#parameter = 2) {
body {
font-style:normal;
}
}
Calls it in Files
//mobile.less
#parameter: 1;
.mixin(#parameter);
//tablet.less
#parameter: 2;
.mixin(#parameter);
Notice that we are still working with a "global" #parameter variable that is just being passed in as a "local" variable of the same name to the mixins. So all we gain here is more code (the addition of the local variable) to do the same thing.
Now assuming you are really after modifying the final output css behavior through the user input, then you may be able to "override" by a later call. This assumes that all the same properties, selectors are set by the various mixin calls, just to different values. So let us assume .mixin(1) is still in "mobile.less", you could set up a "reset.less" file that is called on user input to override by the css cascade.
LESS Mixin Definition Added
.mixin(#parameter) when (#parameter = 0) {
//purposefully empty, used as default for reset.less
}
Calls in your current "mobile.less" etc. remain as they are. You can have a global value of #parameter: 0; set in your global "variables.less" file, and then "reset.less" is this:
//reset.less
.mixin(#parameter);
That way "reset.less" outputs nothing by default (using the mixin definition just done above). This "reset.less" file is put last in the html processing so that it follows any "mobile.less" stylesheets, etc. Then, when the user changes #parameter, the "reset.less" is updated with the new values, and it does output css, which, by virtue of the css cascade, overrides the values of "mobile.less" etc.