最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

javascript - Why is empty object in Vue3 not reactive? - Stack Overflow

programmeradmin2浏览0评论

When I create a ref from an empty object and later add object properties, there is no reactivity:

<template>
  <p>{{hello}}</p>
  <button @click="add()">Click me</button>
</template>

<script>
import {ref} from 'vue';
export default {
  name: "Test",
  setup(){
    const myData = ref({});
    return {myData}
  },
  methods: {
    add(){
      this.myData["text"] = "Hello";
      console.log(this.myData);
    }
  },
  puted: {
    hello(){
      return this.myData.hasOwnProperty("text")) ? this.myData["text"] : "no text";
    }
  }
}
</script>

Clicking the button shows that myData has changed but the puted property hello does not update.

Also tried reactive({}) instead of ref({}) without success.

It works when we initialize the ref with properties, like const myData = ref({"text": "no text"});.

But why does the empty object not work?

EDIT:
Finally found out what exactly the problem is and how it can be solved: The reactivity core of Vue3 is not alert of Object.keys() but only of the values of the properties, and the empty object does not have any. However, you can make Vue3 alert, if the puted property is defined like

puted: {
    hello(){
      return Object.keys(this.myData).indexOf("text") > -1 ? this.myData["text"] : "no text";
    }

The call to Object.keys(this.myData) is needed to make the reactivity system aware of what we are interested in. This is similar to setting a watch on Object.keys(this.myData) instead of watching this.myData.

When I create a ref from an empty object and later add object properties, there is no reactivity:

<template>
  <p>{{hello}}</p>
  <button @click="add()">Click me</button>
</template>

<script>
import {ref} from 'vue';
export default {
  name: "Test",
  setup(){
    const myData = ref({});
    return {myData}
  },
  methods: {
    add(){
      this.myData["text"] = "Hello";
      console.log(this.myData);
    }
  },
  puted: {
    hello(){
      return this.myData.hasOwnProperty("text")) ? this.myData["text"] : "no text";
    }
  }
}
</script>

Clicking the button shows that myData has changed but the puted property hello does not update.

Also tried reactive({}) instead of ref({}) without success.

It works when we initialize the ref with properties, like const myData = ref({"text": "no text"});.

But why does the empty object not work?

EDIT:
Finally found out what exactly the problem is and how it can be solved: The reactivity core of Vue3 is not alert of Object.keys() but only of the values of the properties, and the empty object does not have any. However, you can make Vue3 alert, if the puted property is defined like

puted: {
    hello(){
      return Object.keys(this.myData).indexOf("text") > -1 ? this.myData["text"] : "no text";
    }

The call to Object.keys(this.myData) is needed to make the reactivity system aware of what we are interested in. This is similar to setting a watch on Object.keys(this.myData) instead of watching this.myData.

Share Improve this question edited Mar 27, 2022 at 8:14 Nechoj asked Mar 13, 2022 at 18:26 NechojNechoj 1,5821 gold badge11 silver badges19 bronze badges
Add a ment  | 

2 Answers 2

Reset to default 2

Try to you update your ref object like

this.myData = {"text": "Hello"}

const { ref, puted } = Vue
const app = Vue.createApp({
  /*setup(){
    const myData = ref({});
    const hello = puted(() => myData.value.hasOwnProperty("text") ? myData.value.text : myData.value = "no text")
    const add = () => {
      if(Object.keys(myData.value).length === 0) {
        myData.value = {'text': "Hello"};
      } else {
        myData.value.otherProperty = "Hello again"
      }
    }
    return { myData, add, hello }
  },*/
  setup(){
    const myData = ref({});
    return { myData }
  },
  methods: {
    add(){
      if(Object.keys(this.myData).length === 0) {
        this.myData = {"text": "Hello"}
      } else {
        this.myData.otherProperty = "Hello again"
      }
      console.log(this.myData)
    },
  },
  puted: {
    hello(){
      return Object.keys(this.myData).length !== 0 ? this.myData[Object.keys(this.myData)[Object.keys(this.myData).length - 1]] : "no text"
    }
  }
})
app.mount('#demo')
<script src="https://unpkg./[email protected]/dist/vue.global.prod.js"></script>
<div id="demo">
  <p>{{ hello }}</p>
  <button @click="add">Click me 2 times</button>
</div>

If you change your puted property to be defined such that it references myData['text'] directly before returning, things work as expected:

  puted: {
    hello() {
      return this.myData['text'] || 'no text'; // works
    }

I suspect what's going on with your original code is that the Vue dependency-tracking code is not able to see that your function depends on myData. Consider that hello is being called (by Vue) before the text property exists on the object. In that case, the function returns before actually touching the proxied value (it short-circuits as soon as it sees that hasOwnProperty has returned false).

Dependency tracking in Vue is done dynamically, so if your puted property doesn't touch any reactive variables when called, Vue doesn't see it as having any external dependencies, and so won't bother calling it in the future. It will just use the previously-cached value for subsequent calls.

发布评论

评论列表(0)

  1. 暂无评论