Break Vue's reactivity
YPChen
Posted on February 28, 2023
This article won't do a deep dive into the implementation of Vue.js reactivity, I just want to show some examples that will break the reactivity when you are writing with the framework.
Should you be interested in the mechanism of the reactivity under the Vue.js, here are some information I think that would help:
TL;DR
- Primitive value props cannot be modified from the child component.
- For a prop that is an object, modify its attributes from the child component is possible with both mutation and immutation functions, but the data structures may be different.
-
shallowRef
only updates when a referred source has reassigned.
Two Way Binding
Let's start with a simple input element with a reset button, we can see what we have typed down below the input element.
It works! Not surprising, right? But in reality, we frequently separate elements into child components to make the function of each component clearer. So, let's move the input element and the reset button to Comp.vue
. And it seems Vue is arguing about the prop are read-only.
It's good to see Vue prohibit modifying props "directly", because it usually causes data flow of the states to become a mess.
How about to destructure the props
that is an object type in JavaScript? Deeper to the props.modelValue
's value property. (I add styles to stand out the elements 😁)
-
Vue Playground
- By clicking "Reset" button, you trigger the
restMsg
function in theComp.vue
to clear thevalue
's value to empty string. - By clicking "Resume to default" button, you trigger the
resumeMsg
function in theApp.vue
to reassign an new object to themsg
.
- By clicking "Reset" button, you trigger the
Reassign an object to the msg
breaks the props
's reactivity. As in JavaScript, every object points to a reference of memory, the msg
is not pointing to the same ref of the value
in the Comp.vue
.
Immutation and Mutation
For this part, let's play both mutable and immutable method on two array ref
s to see how we can break the reactivity.
On List.vue
, clicking "Add to ordered list" button will trigger a function to push the value from msg.value
into it. However, clicking "Add to unordered list" button should see a warning message popping out.
As mentioned above, reassign a new array to the ref
via the prop breaks the reactivity which is not allowed.
Unlike states which are all immutable in React, the Vue doc mentions that mutation on
ref
is valid-- Reactivity API: Core #ref | Vue.js.
If you would like the immutation way to update the unorderedlist
, you may need to modify its structure, like what we did to msg
:
// from
const unorderedlist = ref([]);
// to
const unorderedlist = ref({ value: [] });
You should also make some change on the functions:
function addToUList() {
unorderedList.value.value = [...unorderedList.value.value, msg.value.value];
emits('submitMsg');
}
function clearUList() {
unorderedList.value.value = new Array();
}
Shallow Ref
The example below use shallowRef
instead of ref
for the lists
. You can see both add to list button don't make changes on the screen. But if you then click the "restore to default" button, the added items show up suddenly.
As the msg
is used in the List.vue
and the "Resume" button triggered a reassign to the value from the parent-- App.vue
, it also have the lists
to update.
Thanks for reading 🙏
Posted on February 28, 2023
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.