Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Avoid mutating a prop directly... yet this appears to be what the official example does?

I'm writing a recursive tree renderer and suffering this "Avoid mutating props directly" warning.

As I understand it, "props down, events up" means a child can't/shouldn't directly change parent data. I can avoid this error by writing lots of code where one component $emits a change, its parent catches it and re-emits it, and on and on, up to the top level component which finally can change the data, which then renders down through the tree. While I get the use case where a generic component needs to be agnostic of its parent, for a recursive component it seems terribly inefficient.

I noticed an official VueJs 2 tree view example is provided. But looking at that code shows that the child components are passed an object belonging to the parent, yet the child component is allowed to update it directly (e.g. in the addChild or changeType methods).

I made a variation of that jsfiddle as proof. All my variation does is outputs the parent's data as json so you can see it is changed. At the start it looks like this:

{"name":"My Tree","children":[{"name":"hello"},{"name":"wat"}

Then if you click into the first parent, then double click 1. hello to trigger changeType you'll notice the parent's data is now changed:

{"name":"My Tree","children":[{"name":"hello","children":[{"name":"new stuff"}]},{"name":"wat"}... 

...yet the dreaded "Avoid mutating a prop directly" warning was not fired.

So I'm obviously missing some nuance. It's frustrating because there's so many questions about this and I'm afraid of adding a duplicate. But I feel this is different because I'm asking "why is the example given not mutating a prop directly"?!

like image 713
artfulrobot Avatar asked Mar 09 '23 00:03

artfulrobot


1 Answers

Objects and arrays are passed by reference it's perfectly acceptable to mutate the properties of objects or the contents of arrays that are pased as props because that is not changing the reference. Changes to an object's properties will be reflected everywhere that specific reference is used. This is addressed in the official documentation.

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 will affect parent state.

Were you to try to set the object passed in as a property to an entirely different object, the warning would be displayed in the console.

Whether or not you choose take advantage of this is a design consideration. In the Vue tree example, the code mutates the object properties and the changes are reflected everywhere. A counter example might be editing a user. If you had a User component and wanted the changes to that object to only be reflected outside the component once the changes were considered valid (to allow canceling the changes), you would make an internal copy of the object, edit the copy, and emit the changes when they were considered acceptable.

like image 169
Bert Avatar answered Apr 26 '23 02:04

Bert