Monday, June 3, 2024
 Popular · Latest · Hot · Upcoming
-4
rated 0 times [  0] [ 4]  / answers: 1 / hits: 7718  / 2 Years ago, sat, january 8, 2022, 12:00:00

I'm very enthausiast about vuejs but the composition API made me get lost slightly on reactivity:


In a .vue child component a prop is passed (by another parent component), movies:


export default {
props:{
movies: Array
},
setup(props){}

.


Placing in the setup function body of this child component:


A) console.log("props: ",props) // Proxy {}

[above EXPECTED] above tells me that the props object is a reactive proxy object.


B) console.log("props.movies: ",props.movies); // Proxy {}

[above UNEXPECTED] above tells me that the props key 'movies' is a reactive proxy object as well, why? (thus why is not only the main props object reactive? Maybe I should just take this for granted (and e.g. think of it as the result of a props = reactive(props) call)
--> ANSWER: props is a **deep ** reactive object (thanks Michal Levý!)


C) let moviesLocal = props.movies ; // ERROR-> getting value from props in root scope of setup will cause the value to loose reactivity

[above UNEXPECTED] As props.movies is a reactive object, I'd assume that I can assign this to a local variable, and this local variable then also would become reactive. Why is this not the case (I get the error shown above)


D) let moviesLocal = ref(props.movies);
moviesLocal.value[0].Title="CHANGED in child component";

[above UNEXPECTED]
I made a local copy in the child component (moviesLocal). This variable I made reactive (ref). Changing the value of the reactive moviesLocal also causes the 'movies' reactive object in the parent object to change, why is that ? This even holds if I change D: let moviesLocal = ref(props.movies); to let moviesLocal = ref({...props.movies});


Thanks a lot! Looking forward to understand this behaviour


More From » vuejs3

 Answers
9

Important part of understanding Vue reactivity is understanding JavaScript - specifically difference between Value and Reference. If you are not sure what I'm talking about, read the article carefully...


In following examples I will be using props object as it was created following way (in reality it is not created exactly like this but runtime behavior is very similar):


const props = reactive({ movies: [], price: 100 })

B) console.log("props.movies: ",props.movies); // Proxy {}


above tells me that the props key 'movies' is a reactive proxy object as well, why?



Because when Vue creates new reactive object (by wrapping existing object into a Proxy), that conversion is deep - it affects all nested properties (this behavior can be changed by using for example markRaw or shallowRef)


In terms of Value vs Reference the props is a variable holding a reference to a reactive proxy object. That object has a property movies which holds the reference to a reactive proxy of array (arrays are also technically Objects)


C) let moviesLocal = props.movies ; 
// ERROR-> getting value from props in root scope of setup will cause the value to loose reactivity


As props.movies is a reactive object, I'd assume that I can assign this to a local variable, and this local variable then also would become reactive. Why is this not the case



Variables are not reactive. Only Objects can be reactive. In this case moviesLocal variable is assigned with reference to same reactive object as props.movies (moviesLocal === props.movies returns true). This object is still reactive.


Let's use our moviesLocal variable in the template to render some kind of list...


If for example parent mutates the array referenced by props.movies (adding new item with push(), assigning different value to props.movies[0] etc.) child will be notified about the change and its template will re-render.


So why the error? Where is the "loose reactivity" ? Problem is what happens when parent replaces the value of props.movies with differentnew array. Our moviesLocal variable will still hold the reference to previous reactive array. Our child component will still be reactive to changes (mutations) of that original array but lost the ability to react to changes of props.movies property.


This is demonstrated in this demo


The funny thing is that in the core, this behavior has nothing to do with Vue reactivity. It is just plain JS. Check this:


const obj = {
movies: ['Matrix']
}
const local = obj.movies
obj.movies = ['Avatar']

What is the value of local at this point ? Of course it is ['Matrix']! const local = obj.movies is just value assignment. It does not somehow magically "link" the local variable with the value of obj.movies object property.


D) let moviesLocal = ref(props.movies);
moviesLocal.value[0].Title="CHANGED in child component";


I made a local copy in the child component (moviesLocal). This variable I made reactive (ref).



Again, variables are not reactive. Objects they point to (reference) can be reactive. Array referenced by props.movies was already reactive proxy. You just created a ref which holds that same object



Changing the value of the reactive moviesLocal also causes the 'movies' reactive object in the parent object to change, why is that ?



Because both point to (reference) same array (wrapped by Vue proxy) in the memory. Assign a new array to one of them and the this "link" will break...


[#519] Wednesday, December 29, 2021, 2 Years  [reply] [flag answer]
Only authorized users can answer the question. Please sign in first, or register a free account.
theron

Total Points: 168
Total Questions: 93
Total Answers: 94

Location: South Georgia
Member since Fri, Nov 13, 2020
4 Years ago
;