DEV Community

YPChen
YPChen

Posted on • Edited on

Break Vue's reactivity

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:

  1. Reactivity in depth | Vue.js
  2. Vue 3 Reactivity | Vue Mastery
  3. Vue JS 3 Reactivity Fundamentals - Composition API by Marius Espejo

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 the Comp.vue to clear the value's value to empty string.
    • By clicking "Resume to default" button, you trigger the resumeMsg function in the App.vue to reassign an new object to the msg.

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 refs 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: [] });
Enter fullscreen mode Exit fullscreen mode

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();
}
Enter fullscreen mode Exit fullscreen mode

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 🙏

Top comments (0)