The guidance in Vue 3 documentation and in folk literature is that ref() is for scalars and primitives, while reactive() is for Objects.
However, in JavaScript, arrays are a special case of Object. Notwithstanding issues such as monitoring nested object elements for new property additions and other wrinkles, is there a best practice on whether to handle arrays as ref or reactive, whether from a performance perspective or any other?
I would use ref for primitive values as you already mentioned. For object type (objects or Arrays), I would advice to use the reactive property. This makes your code easier to read and removes the ".value" you would have to add when using the ref property.
I would say, only use ref when you cannot use reactive. In your template they are pretty much the same because ref is automatically unwrapped. But in your code you have to remember that anything you created with ref will be a Ref - you need to manually unwrap it by calling .value, for most of the time.
You can ref around arrays and objects, but you still need to call .value afterwards. ref(x) does not "upgrade" automatically to reactive(x) just because x is an object (even though internally ref(object) might be calling reactive at some point).
There are a few cases when you don't need to manually unwrap, e.g. if you assign your ref to a property of a reactive object. But this is actually what makes it confusing and error-prone.
Btw if you use typescript, reactive around primitives will report error right away and that is the time you know you need to use ref.
Related
Here's the story...
We're building a vanilla JS agent-based simulation engine. The user interacts with said simulation via a Vue JS UI. In the engine, there are many different subclasses of the simulation's most important class "object". Every object and subclass are defined by a set of values that exist on a dictionary called "Props". Each subclass' behavior is a variation of different methods and what they do with those Props. Anyway, the user is expected to be able to change those values (obj.Props.xpos, obj.Props.ypos, or obj.Props.opacity ... so on and so forth) and see those props change when they interact with some other agent in the simulation. Our original solution to this was to use Vue JS' reactive method to turn this Props property into a Proxy object, like so:
newActiveGraphic.Props = reactive(newActiveGraphic.Props);
However, it seems as though this only works in some cases. For example...
(sim) Creates new object.
(sim) Reports new object to VueX.
(VueX) Replaces object's Props with a reactive object.
(Vue) Gets object from VueX and displays Props to the user.
However, there are times when the Props object reverts to a normal object even after this conversion has taken place. My question is regarding the Proxy standard:
Are there events where a Proxy object will be reverted to its target?
Is there ever a reason why a property of a vanilla object cannot be a Proxy object?
It at first seemed this might have been a side-effect of our code somewhere, but there are no assignments to obj.Props other than at step 3 in the process above.
I learned vuejs recently and I seem to be having problems in fully grasping the essential differences between the usage of ref and reactive. When is it right to use ref or reactive?
Based on this article from Anthony Fu (a Vue.js champion) we can summarize it in these points:
refs are considered as primitives values
reactives as objects
refs only mutated by .value property, but reactive with any nested property
reactives looks like plain objects
reactive objects have some caveats like loosing reactivity when they are destructed.
reactive objects should be wrapped with function when they're watched like watch(()=>reactiveObj,(newVal,oldVal)...., unlike refs which are unwrapped watch(refProp,(newVal,oldVal)....
Conclusion :
I’d say go with ref whenever you can
I'm working on a React + redux + Immutable.js + reselect application. I'm considering a design where I'm using Immutable.js in the reducers and sagas, but don't want to couple this library with the smart components, so my presentational part of the app as clean as possible.
According to redux documentation your selectors should always return Immutable object.
My idea is to compute derived state in reselect selector and return plain JS object. If I use memoized selector, new object won't be created on every call if underlaying part of redux state is the same, so my component won't be rerendered unless needed.
I know that I'll partially pay with composability, since the selector cannot be uses as an input for other Immutable.js-ready selectors, but I'll get much cleaner smart components.
Are the any other drawbacks of such solution?
Why does redux documentation so strongly encourages to push Immutable object to smart components?
Are the any other drawbacks of such solution?
toJS is an expensive operation, even if memoized. The argument is why toJS if you don't have to?
Why does redux documentation so strongly encourages to push Immutable object to smart components?
The aforementioned, plus it makes reasoning about the whole redux pipeline easier, i.e. any mutations (side effects/morphisms) to state are easier to wrap one's head around as there's a clear flow and point where changes occur.
With all that said, it comes down to preference and where one feels the bottlenecks/trade-offs in one's architecture are. If you feel having a clean separation outweighs the potential risks/caveats with having toJS in the selector, then that's the correct call for your architecture.
On a side note regarding loss of composability in the selector, you could always have two selectors, one that returns the immutable state--used for selector composition, and one that uses the immutable state selector and calls toJS, where appropriate.
Are the any other drawbacks of such solution?
toJS is expensive and also debugging the application becomes more complex.
Why does redux documentation so strongly encourages to push Immutable object to smart components?
Immutable objects are validated more deeper than plain Objects. In case of oldObject === newObject validation plain objects will be compared on a global level whereas oldImmutableObject === newImmutableObject is compared more deeper. This is more efficient on the render tree avoiding unnecessary updates on rendering React components.
Easy to modify objects with helper functions. get, set and more.
Unnecessary data copying is avoided.
in ES6, there are additional ways to declare a variable such as let and const
A variable declared with const cannot be re-assigned or re-declared.
Why are there so many const declarations in React application and what are the distinctive benefits from using const over var and let?
First answer by #Carcigenicate explains the usage of const correctly.
But const keyword alone is not sufficient to achieve immutability.
e.g. You can mutate a const array :
const a = [12,14,15];
a[0] = 13; // allowed. but mutate a value.
To achieve immutability to object at property level, new JS provide using Object.freeze(), .assign() etc or you can also utilize new library like immutableJS (there are few more good one to check out).
About Immutability in React, React components are pure functions. They accept props and return view.
Pure functions are foundation of Functional Programming. They lead to all sort of benefits (enable composition, simple to comprehend the unit of code which is function, easy to test and many more). Pure function does not have any side effect. It must not modify argument object also, and treat it as immutable.
DOM created by React components forms virtual DOM, and detects the data change called via setState only. On call of setState, it reacts and trigger its real DOM update algorithm. If a developer updates props, this won't happen. This post explain this: http://teropa.info/blog/2015/03/02/change-and-its-detection-in-javascript-frameworks.html
React encourages one way data flow, Updated State flow down from top to bottom as props, and reaction to user action flow up as method call. One way data flow make it easy to debug/understand the react apps.
I created following diagram to understand the example illustrated in official React docs
It's pretty common to have multiple parts of code relying on the same variable (PI for example) . If that variable is a constant, and immutable, you dont need to worry about it changing at unpredictable times based on who may potentially be writing to it.
If a variable shouldn't change, it should be made a constant to ensure that it it isn't reassigned accidentally. That way you can trust that the value of the variable will always be the same.
Note, const has very little to do with immutability. Even if you have a constant reference to an object, the object itself can still change.
I understand that call allows you to pass in an object in place of the 'this' that the method was invoked upon.
"abc".charAt.call("defgh",1);
"e"
But suppose I want the length property to be applied to that object
I can't say
"abc".length.call("defgh");
i'll get an error
Can I do it for a property e.g. length?
Added [since this addition, the 3 answers I see to this question are all good]
It appears some people have thought I was questioning how to invoke a property (which makes no sense). I am not.
And some have thought that I was suggesting that "z".charAt("asdf",0) is better than "asdf".chatAt(0) I am not.
What I am saying is that you can use call on a method to cause it to execute/evaluate on a different object. I could give a more useful example if you really need to see a more useful example.
[1].forEach.call("asdf",function(x){console.log(x+x);});
or
Array.prototype.forEach.call("asdf",function(x){console.log(x+x);});
So forEach can be more concise than a For loop.
So there, even though initially the example I gave for call was not useful, lo and behold, a useful example can exist.
So too, that may be the case with a property
I may want to apply a different object, for a property e.g. 'length' to evaluate on. That should not be impossible in theory(as one answerer suggested before deleting his answer). I don't have a particular use I can come up with that would be beneficial for evaluating a property on a different object, but it should not be impossible.
And just because I don't have a use for it, doesn't mean it should be thrown away. Remember that prior to giving a good usage for call on a method, some said it's pointless, then I gave potentially be a use for it. And that's no argument for it being impossible in theory/principle.
There is no equivalent way to take the functionality behind the .length property and apply it to a different object. Javascript does not have that feature.
Part of the reason is because a property can be just a static value stuck in a property on an object, so there's meaning to evaluate the "ttt".length property on another object. You can access the .length property on another object, but there's no semantic meaning to using the "ttt" object's .length property on another object. The only semantic thing you have is a name. You can use that name on another object as in obj2["length"] or obj2.length, but all you've borrowed from the "ttt" object is the name of the property. It's different with functions that are methods on objects. They are executable code that is passed a this value as context. .call() allows you to take any function (whether a method or not) and specify the value of this when it is executed by using .call(). That's why you can take a method on one object and call it in the context of another object. But, a plain (non-function) property just doesn't have that capability. There's nothing to "execute" in a different context. The property just has a name and a value. You can use the name on any other object, but there's no code you can execute in a different context for that property.
Also, keep in mind once you've retrieved "ttt".length, all you have at that point is a number. That number has no context about where it came from so there isn't really any way to apply the logic that generated that number to some other object.
As for .call(), it is a method of a Function object. So, you can only use it with functions. That's why it works fine with the .charAt() method because that's a function.
But the .length property is not a function (it returns a number) so it does not have a .call() method. That's why what you're trying does not work.
Because .length is not a function, you cannot take the functionality behind it and arbitrarily apply it to another object the way you tried to do with .charAt(). That simply isn't supported with non-functions.
You can, of course, just use the .length property that is already on your other string as in:
console.log("defgh".length);
If you can describe what you're really trying to accomplish, we can probably offer a different way to do it that is supported, but your current description of what you're trying to do does not really seem logical so it's hard to figure out what the actual problem is you're trying to solve.
FYI, there's really no reason to have done this either:
"abc".charAt.call("defgh",1);
You might as well just do the much more direct scheme of calling a method on the desired object:
"defgh".charAt(1); // "e"
It is technically impossible in JS since after the "abc".length expression is evaluated the property name is lost (and only the value is carried over next), hence you cannot re-apply it to the another context.
So even if you extended the primitive type wrapper prototypes - you still would not be able to extract something more but the value.
So it just does not fit into the current language specification.
The purpose of call and apply is to set the this object within a function call. They are necessary for calling functions as methods of objects that don't have that method. However, the caveat is that the object supplied as this can be used by the function.
Applying that principle to properties means trying to read a property of an object that doesn't have it, using the algorithm from some other object that does.
If you consider the length property that many objects have, the algorithm for determining it is very different for each type of object:
String: number of characters
Number: undefined
Function (built–in): as defined in ECMA-262
Function (native, not built–in): number of arguments
Array: whatever has been set, but always at least 1 greater than highest index if there is one
and so on. So which should be the generic version returned of there was an equivalent of call for properties? So There is a very large matrix of property algorithms and objects to apply them to.
However don't despair! If you wish to use, say, the String version of length for some object, then convert it to a string and get its length. E.g. the string version of length for an array might be:
someArray.join('').length;
So you can define the algorithm for such properties any way you like. ;-)
PS. getters allow you to do this on a per object basis, but they can't be shared.