2.5.11
https://jsfiddle.net/7gmh5wL8/1/
I expect, that my data and props enumerable properties will not be invoked, without my explicit call for them.
Seems, that defineReactive function in /src/core/observer/index.js works that way, that it accepts an object property value, instead of getting it from the getter on demand. Despite the fact, that it uses getOwnPropertyDescriptor to respect user-defined getters and setters.
I faced this problem in a context of lazy-loaded backend entities. I have some redux store selectors, that returns RESTfull models. Some of the models nested properties are wrapped into getters, so I can call them, if needed and trigger a background api request for additional info. Now, all of the getters are invoked immediately and a bunch of requests is sent after initial rendering.
I can do a pull request, to fix this, but may be I do not understand some concept under this behaviour.
Sorry for bad english.
I don't think there is any guarantee regarding when getters will be invoked. In this case we need to traverse and observe the returned value from getters too, so we have to invoke the getter.
Also - it's a very bad idea to rely on getters for side effects. Getters should be pure.
@yyx990803, Sorry, I didn't get that thing about guarantee. I don't suggest not to traverse these properties, but why should we get the value of the property in walk, despite the fact, that it is used only if the property has no getter?
I see, that the val parameter is necessary in other method use-cases, but for walk function, I think, it can be omitted without any harm and should be calculated only, if property has no getter.
Thank you, I'm aware of that getters thing, but I'm using it carefully for saving development time. This is not the only reason, I think this change is usefull. May be, it is not a common use-case of using getters in props and data, but for those, who does it, it can be a source of lags(for some costly getter functions), or some other unintended behaviour.
@yyx990803 @DeyLak
When a property of a data object only has getter:
const data = {}
Object.defineProperty(data, 'getterProp', {
enumerable: true,
configurable: true,
get: () => {
return {
a: 1
}
}
})
After processing by the defineReactive function, the data.getterProp property will have both a getter and a setter.When trying to set the value of the data.getterProp property, the later defined set function will be executed and the new value will be observed.However, this observed new value will never be relied upon.
I think we should modify the set method as shown in the following code:
set: function reactiveSetter (newVal) {
const value = getter ? getter.call(obj) : val
/* eslint-disable no-self-compare */
if (
(getter && !setter) ||
newVal === value ||
(newVal !== newVal && value !== value)
) {
return
}
/* eslint-enable no-self-compare */
if (process.env.NODE_ENV !== 'production' && customSetter) {
customSetter()
}
if (setter) {
setter.call(obj, newVal)
} else {
val = newVal
}
childOb = !shallow && observe(newVal)
dep.notify()
}
Add judgment conditions: (getter && !setter).The existence of getter ensures that the property is an accessor property.If an accessor property does not have a setter, the set method should return directly.
@HcySunYang feel free to submit a PR
Ok, I will submit a PR
Most helpful comment
@yyx990803 @DeyLak
When a property of a data object only has
getter:After processing by the
defineReactivefunction, thedata.getterPropproperty will have both agetterand asetter.When trying to set the value of thedata.getterPropproperty, the later definedsetfunction will be executed and the new value will be observed.However, this observed new value will never be relied upon.I think we should modify the
setmethod as shown in the following code:Add judgment conditions:
(getter && !setter).The existence ofgetterensures that the property is an accessor property.If an accessor property does not have asetter, thesetmethod should return directly.