I'm not new to Vue.js, but I'm going through the docs again, trying to pick up on anything I missed the first time. I came across this statement in basic example section of using computed properties:
You can data-bind to computed properties in templates just like a normal property. Vue is aware that vm.reversedMessage depends on vm.message, so it will update any bindings that depend on vm.reversedMessage when vm.message changes. And the best part is that we’ve created this dependency relationship declaratively: the computed getter function has no side effects, which makes it easier to test and understand.
The part about we’ve created this dependency relationship declaratively: the computed getter function has no side effects, isn't clear to me. I do understand that a side effect is some action happening that is not directly related to the pure intentions of the function, but I'm not clear how it's being used in this statement.
Could someone explain further what the opposite could be? What are the potential side effects that could be happening?
The term side effect here refers to any data mutations performed in the computed property getter. For example:
export default {
data() {
return {
firstName: 'john',
lastName: 'doe',
array: [1,2,3]
}
},
computed: {
fullName() {
this.firstName = 'jane'; // SIDE EFFECT - mutates a data property
return `${this.firstName} ${this.lastName}`
},
reversedArray() {
return this.array.reverse(); // SIDE EFFECT - mutates a data property
}
}
}
Notice how fullName mutates firstName, and reversedArray mutates array. If using ESLint (e.g., from Vue CLI generated project), you'd see a warning:
[eslint] Unexpected side effect in "fullName" computed property. (vue/no-side-effects-in-computed-properties)
[eslint] Unexpected side effect in "reversedArray" computed property. (vue/no-side-effects-in-computed-properties)
demo
Related
In the Vue docs there is a section on one-way data flow: https://v2.vuejs.org/v2/guide/components-props.html#One-Way-Data-Flow
Here it explains that you should not mutate a prop. Additionally, it says:
The prop is used to pass in an initial value; the child component wants to use it as a local data property afterwards. In this case, it’s best to define a local data property that uses the prop as its initial value:
At the bottom of this section, there is a note that says:
Note that objects and arrays in JavaScript are passed by reference, so if the prop is an array or object, mutating the object or array itself inside the child component will affect parent state.
I’m considering the situation where you have a prop that is an object (or an array) and you have defined a local data property that uses the prop as its initial value:
props: {
initialMyObject: {
type: Object,
required: true
}
},
data() {
return {
myObject: this.initialMyObject
}
}
If I mutate the data item myObject, since it is an object the prop itself will end up getting mutated. Is this therefore the same essentially as “mutating a prop” and to be avoided? Would it be preferable in this case to emit an event whenever a change to the object is desired (or to use Vuex)?
Thanks in advance for your help on this.
You can simply clone it though -
data() {
return {
myObject: {...this.initialMyObject}
}
}
To avoid it.
But yeah you just can't reassign a value to a prop as
It's just because Object is kind of reference memory. When you have Array or Object stored in any variable it's a reference variable.
Memory management in such case, The reference variable will points to a memory address in heap so you can add more n more value to address. However you cannot just replace that address with any new value even with the new address.
In my preference, You should prefer Vuex, whenever you want a value to get updated for whole project
I would like to understand when you can use a computed property like this:
computed: {
selectedDate () {
return this.$store.getters['stockProposal/getDateEndArticle']
}
}
Where the getter is defined as follows:
getDateEndArticle: state => {
return state.articleSettings['date_end']
}
Where in the template I then use:
v-model="selectedDate"
Sometimes this works for me, but often I get the following error 'Property or method "selectedDate" is not defined on the instance but referenced during render.'
Can someone explain to me why this is not always working?
I also tried to follow this tutorial: https://itnext.io/anyway-this-is-how-to-use-v-model-with-vuex-computed-setter-in-action-320eb682c976. But even with a computed setter added, I still get the same error. While I am doing exactly this: https://vuex.vuejs.org/guide/forms.html#two-way-computed-property.
There are couple of questions related computed properties like the following
"vuejs form computed property"
"Computed properties in VueJs"
"computed property in VueJS"
"Use computed property in data in Vuejs"
They are asking about specific error or logic. There are lot of websites that are explaining about vuejs related concepts. I read about computed properties on vuejs official website. When we do complex calculations or want to avoid to write more logic in our html template then we use computed properties.
But could not get any solid understanding about computed properties, when it calls, how it calls, what exactly do?
TL;DR: Computed properties are getters/setters in Vue.
When defined in the shorthand form, they are getters:
computed: {
someComputed() {
return `${this.foo} ${this.bar}`;
}
}
is equivalent with
computed: {
someComputed: {
get: function() {
return `${this.foo} ${this.bar}`;
}
}
}
which can also have a setter:
computed: {
someComputed: {
get: function() {
return `${this.foo} ${this.bar}`;
}
set: function(fooBar) {
const fooBarArr = fooBar.split(' ');
this.foo = fooBarArr[0];
this.bar = fooBarArr[1];
}
}
}
In short, Vue computed properties allow you to bind an instance property to
a getter: function run when you look up that property; usage:
this.someComputed // returns the computed current value, running the getter.
a setter: function run when you attempt to assign that property; usage:
this.someComputed = value; // sets the computed current value, running the setter.
Read more on getters and setters in Javascript.
And here's the documentation on Vue computed properties.
You can use computed properties when for example you have some logic what will blow up your template.
The idea is, that normally you want to keep all javascript logic in the javascript side of your vue component, and only access final data in your data (if possible)
For that you can use computed props, which normally are doing simple things like:
computed: {
// a computed getter
reversedMessage: function () {
// `this` points to the vm instance
return this.message.split('').reverse().join('')
}
}
Or an another good example if you have some currency and you want to format it with thousand separator and euro ign at the end.
Then you can access your computed prop in the template like you access a normal prop, you dont have to call it as a function.
like so:
<div>{{reversedMesage}}</div>
Every time, when any variable what is used in your conputed prop is changing, vue vill take care of it and will re-calculate your computed property again.
Lets say you have the following:
computed: {
prettyAmount: function () {
return this.amount + ' ' + this.currency.toUpperCase()
}
}
<div>{{prettyAmount}}</div>
Whenever currency or amount changes, the output of prettyAmount will be changed as well.
I'm creating my own template based widgets and I was trying to pass some objects through the constructor on creation like this
var widget = new myWidget(obj1, obj2, obj3);
where my constructor of the widget looks like
constructor: function(param1, param2, param3)
However I was getting some errors and found they were due to _WidgetBase functionality (specifically the create method) that is expecting something special in the first and second parameters.
create: function(params, srcNodeRef)
So in order to avoid my parameters nuking the params, and srcNodeRef that was expected in position one and two, I had to move my parameters to after the second position like this
constructor: function (params, srcNodeRef, myParam1, myparam2, myParam3)
But naturally this is not an expected way to solve this compared to the usual way to instantiate objects in normal object oriented languages (ex. c#)
My question is, is there a recommended pattern for passing initialization parameters to a custom widgets constructor, that avoids this issue of having to remember the first and second parameter positions are reserved?
NOTE:
An important note is that whatever parameters I send into the widget, must be acted on or made available before postCreate executes, just like it is if I passed them to the constructor.
Actually, there is a "dojo" way to pass parameters into your widget:
var widget = new myWidget({obj1: obj1, obj2: obj2});
In instance of your widget these object will refer to
this.obj1, this.obj2. You don't have to override constructor.
Some comments from dojo source of _WidgetBase on this topic:
//////////// INITIALIZATION METHODS ///////////////////////////////////////
/*=====
constructor: function(params, srcNodeRef){
// summary:
// Create the widget.
// params: Object|null
// Hash of initialization parameters for widget, including scalar values (like title, duration etc.)
// and functions, typically callbacks like onClick.
// The hash can contain any of the widget's properties, excluding read-only properties.
// srcNodeRef: DOMNode|String?
// If a srcNodeRef (DOM node) is specified:
//
// - use srcNodeRef.innerHTML as my contents
// - if this is a behavioral widget then apply behavior to that srcNodeRef
// - otherwise, replace srcNodeRef with my generated DOM tree
},
=====*/
I +1'd Kirill's answer as that's the easiest. But from the other comments it sounds like you might need to massage the input or initialize other variables based on the input.
If so, take a look at the postMixinProperties lifecycle method and override it in your widget. If your widget is templated and the template expects the massaged data, you'll need this. In here you refer to your properties with this as you expect.
postMixInProperties: function(){
// summary:
// Called after the parameters to the widget have been read-in,
// but before the widget template is instantiated. Especially
// useful to set properties that are referenced in the widget
// template.
// tags:
// protected
},
Don't forget to invoke this.inherited(arguments); in here as you should in all of the dijit lifecycle methods.
Defining setters for you properties is another way to massage these properties. You'll want this if a template will use these properties. Example of a setter from the Writing Widgets page. So here 'open' would be the name of the parameter as passed to the contructor, or in a widget template.
_setOpenAttr: function(/*Boolean*/ open){
this._set("open", open);
domStyle.set(this.domNode, "display", open ? "block" : "none");
}
Below documentation shows the usage of Observable with and without the "new" keyword.
http//dojotoolkit.org/reference-guide/1.9/dojo/store/Observable.html
// create the initial Observable store
store = new Observable(new Memory({data: someData}));
http//dojotoolkit.org/documentation/tutorials/1.6/realtime_stores/
Note: despite its capital "O" and dedicated module, dojo.store.
Observable is not a constructor; it is simply a function which
takes a store, wraps it with observe functionality, then returns it.
Therefore, the new keyword should not be used with dojo.store.Observable.
http://dojotoolkit.org/documentation/tutorials/1.7/realtime_stores/
// wrap the store with Observable to make it possible to monitor:
marketStore = Observable(marketStore);
What is the correct usage?
If both are correct? when should a particular usage be preferred over the other.
Frank.
It doesn't really matter. What happens behind the screens is very similar. When you call the Observable as a function like:
var store = Observable(new Memory({ data: [] }));
Then it will use return value of the Observable() method (which is the observable store).
When you're using the new keyword, you're creating a new instance of Observable, in JavaScript that means that the Observable() function itself will be seen as the constructor of the new instance.
However, when you're providing a return value from inside the constructor, that object (when being a complex object) is used as the instance in stead. So in this case it returns the observable store, so that will be used as the instance. A good article to read what happens if something is being returned from a constructor function can be found here.
The naming of it (starting with a capital letter) makes you think it's an instance of Observable, but it isn't. The ultimate proof to that is the following:
new Observable(new Memory({ data: [] })) instanceof Observable // Returns false
The following returns false and in case of a real instance it would return true.
Summarized, both ways will return an observable store. There is no difference in it, even performance wise both are very similar.
So it doesn't really matter what you use, the only thing I can tell you is that it behaves like a normal function and not as a constructor.