javascript - How to update reactive Objects (and properties in general)? - Stack Overflow

Vue.js documentation on Reactivity in Depth mentions thata property must be present in the data object

Vue.js documentation on Reactivity in Depth mentions that

a property must be present in the data object in order for Vue to convert it and make it reactive

(...)

you have to initialize Vue instances by declaring all root-level reactive data properties upfront, even just with an empty value

Consider these two code snippets, where tags is defined as an empty object and updated in the course of the script, in two different ways:

var vm = new Vue({
  el: "#root",
  data: {
    tags: {}
  }
});

vm.tags = {
  hello: true,
  world: true
};
<script src=".3.3/vue.js"></script>
<div id="root">
  {{tags}}
</div>

Vue.js documentation on Reactivity in Depth mentions that

a property must be present in the data object in order for Vue to convert it and make it reactive

(...)

you have to initialize Vue instances by declaring all root-level reactive data properties upfront, even just with an empty value

Consider these two code snippets, where tags is defined as an empty object and updated in the course of the script, in two different ways:

var vm = new Vue({
  el: "#root",
  data: {
    tags: {}
  }
});

vm.tags = {
  hello: true,
  world: true
};
<script src="https://cdnjs.cloudflare./ajax/libs/vue/2.3.3/vue.js"></script>
<div id="root">
  {{tags}}
</div>

var vm = new Vue({
  el: "#root",
  data: {
    tags: {}
  }
});

vm.tags["hello"] = true
vm.tags["world"] = true
<script src="https://cdnjs.cloudflare./ajax/libs/vue/2.3.3/vue.js"></script>
<div id="root">
  {{tags}}
</div>

In the first case, the content is correctly updated, and in the second - not.

Why is it so, despite the fact that in both cases tags were declared at the VM instantiation?

Share Improve this question edited Jul 14, 2022 at 0:54 tony19 139k23 gold badges278 silver badges347 bronze badges asked Jun 3, 2017 at 16:10 WoJWoJ 30.1k58 gold badges214 silver badges405 bronze badges 0
Add a ment  | 

2 Answers 2

Reset to default 6

It's not that the tags object is declared, it's that the properties on the tags object do not exist when the Vue is instantiated.

In the second case you are adding two new properties to the tags object by using an indexer. Vue cannot detect that those properties were added.

This is why the $set method exists. When you add a new property to an object, you need to add it via $set or Vue.set

 Vue.set(vm.tags, 'hello', true)

or, if you are inside a Vue method,

this.$set(this.tags, 'hello', true)

In the first case, you are adding a pletely different object that has the properties. That being the case, Vue is aware of the properties and converts them into reactive properties when the new value is added to data.

If instead you added a new empty object and then added the properties, you would be back in the same case as your second example.

Typically, you just want to initialize the object with the empty properties.

data: {
    tags:{
        hello: false,
        world: false
    }
}

In which case, the properties will be converted to reactive properties and changes will be detected.

Edit

@WoJ posted a ment with a pen with code that looks like this:

var vm = new Vue({
  el: "#root",
  data: {
    posts: {},
    tags: {}
  }
});

vm.tags = {
  hello: true,
  world: true
};

vm.posts["bonjour"] = true
vm.posts["monde"] = true
<script src="https://cdnjs.cloudflare./ajax/libs/vue/2.1.10/vue.min.js"></script>
<div id="root">
  <!-- show all tags which are on -->
  {{tags}}
  {{posts}}
</div>

In this code it appears that the posts property of the Vue is updated with new reactive properties because they are displayed in the output when the Vue is rendered. What is happening here is that the properties are added to the posts object, that's just how javascript works, you can add properties to objects, but Vue doesn't know they are there. More specifically, these properties are not added as reactive properties (getters/setters) which is how Vue knows when changes occur to data that has been added to the Vue. In fact, adding these properties to the posts object does not trigger a render.

So, why do the new properties show up in the output? The reason the new posts properties show up in the output is because setting the tags property to a new object triggers a render to be scheduled. It's important to know that Vue renders are not synchronous, they are asynchronous (see here).

... Vue performs DOM updates asynchronously. Whenever a data change is observed, it will open a queue and buffer all the data changes that happen in the same event loop.

For example, when you set vm.someData = 'new value', the ponent will not re-render immediately. It will update in the next “tick”, when the queue is flushed.

In the code example above, the update to tags triggers a render to be scheduled. Then, the posts object is updated with two new properties that are not converted to reactive properties because Vue doesn't know they exist. Then some time later, the scheduled render occurs and Vue updates the HTML with the current state of the objects in data. Since posts does have those two new properties, those properties are rendered to the screen. Updates to those properties, however, will never trigger an update to render.

To see this is the case, simply ment out the update to the tags property.

var vm = new Vue({
  el: "#root",
  data: {
    posts: {},
    tags: {}
  }
});

//vm.tags = {
//  hello: true,
//  world: true
//};

vm.posts["bonjour"] = true
vm.posts["monde"] = true
<script src="https://cdnjs.cloudflare./ajax/libs/vue/2.1.10/vue.min.js"></script>
<div id="root">
  <!-- show all tags which are on -->
  {{tags}}
  {{posts}}
</div>

Notice, in this case, the rendered Vue never changes.

This is because in the first case, you are running a setter on tags (because you are reassigning it) - which Vue has wrapped and can detect. In the second case, you're running setters on nested properties that were not in your data: { tags: { definition, so they are not reactive.

The Change Detection Caveats section in the documentation covers this, though not exactly the same as your case (the nested properties situation). You would have to declare your data like:

data: {
  tags: {
    hello: null,
    world: null,
  }
}

发布者:admin,转转请注明出处:http://www.yc00.com/questions/1744755127a4591834.html

相关推荐

发表回复

评论列表(0条)

  • 暂无评论

联系我们

400-800-8888

在线咨询: QQ交谈

邮件:admin@example.com

工作时间:周一至周五,9:30-18:30,节假日休息

关注微信