Home > front end >  Why does shallowReactive not work as expected?
Why does shallowReactive not work as expected?

Time:07-20

I am new to vue3 and have some confusion about shallowReactive.

only root-level properties are reactive for a shallow reactive object.

But when I click the add button, the value of count2 will still change:

<script setup>
import { shallowReactive } from 'vue'

const test = shallowReactive({
  count1: 0,
  nested: {
    count2: 0
  }
})
const add = () => {
  test.count1  
  test.nested.count2  
}
</script>

<template>
  <button @click="add"> </button>
  <div>{{ test.count1 }}</div>
  <div>{{ test.nested.count2 }}</div>
</template>

CodePudding user response:

When you modify something nested inside a shallowReactive it doesn't mean the mutation is not performed. It only means Vue is not told: you need to check for differences between M (model) and V (view/template/DOM) now.

Because you're also changing test.count1 in the same function, which is watched, the component gets diff-ed. The diff-ing doesn't care what's reactive. It only looks for differences between M and V. If it finds any, it updates them.

Let's make separate functions for nested and non-nested props. As you can see, V only updates when the non-nested prop is changed. At that point, the entire view (template) is checked and updated according to model:

const { createApp, shallowReactive } = Vue;

createApp({
  setup() {
    const test = shallowReactive({
      count1: 0,
      nested: {
        count2: 0
      }
    })
    const add = () => {
      test.count1  
    }
    const addWithoutUpdate = () => {
      test.nested.count2  ;
    }
    return { test, add, addWithoutUpdate }
  }
}).mount('#app')
<script src="https://cdnjs.cloudflare.com/ajax/libs/vue/3.2.37/vue.global.prod.min.js"></script>
<div id="app">
  <button @click="add"> </button>
  <button @click="addWithoutUpdate">Only add to nested</button>
  <div>{{ test.count1 }}</div>
  <div>{{ test.nested.count2 }}</div>
</div>


In other words, shallowReactive doesn't freeze the nested objects. They can be mutated. But Vue will only diff the template when something it actually watches changes. Could be the top level of this shallow reference or some other, completely unrelated reactive variable.

  • Related