This is my participation in August the third day of challenge We’re using the vue do development process, often encounter some “weird” event, I clearly binding data, why have no response, there are often developed in the use of TDF also encountered such a problem, he felt clearly write no problem, why not response data, It must be a bug in VUE. Is it true? Let’s take a look at some code

<template>
  <div>
    <div>
      <span>User name: {{userinfo.name}}</span>
      <span>User gender: {{userinfo.sex}}</span>
      <span v-if="userInfo.officialAccount">Public account: {{userinfo.OfficialAccount}}</span>
    </div>
    <button @click="handleAddOfficialAccount">Add an official account</button>
  </div>
</template>
<script>
export default {
  data() {
    return {
      userInfo: {
        name: 'Ming'.sex: 'male'}}},methods: {
    // Add the user's official account here
    handleAddOfficialAccount() {
      this.userInfo.officialAccount = 'Interesting front end'}}}</script>
Copy the code

In the code above, we hope to the user information, add the public property, but by enclosing the userInfo. OfficialAccount = ‘front end is very interesting’ add after, is not effective, why is this? In Vue, we use object.definePrototype to listen for getters and setters on each key of the Object. We can only listen for existing properties. We can’t listen for new properties. Here are four ways to do this.

1. Define the attributes to be added in data in advance

For example, the public number above, I can define in advance in userInfo, so that it is not new attributes, like the following

data() {
    return {
      userInfo: {
        name: 'Ming'.sex: 'male'.// I'll define it in advance
        officialAccount: ' '}}}Copy the code

2. Replace userInfo directly

It is not possible to add new attributes to userInfo, but since userInfo is already defined, I can simply change the value of userInfo, so I can write as follows

this.userInfo = {
  // Copy the original userInfo into the new object using the extended operation
	// The ES6 extension operator is used. this.userInfo,// Add new attributes
  officialAccount: 'Interesting front end'
}

Copy the code

3. Using the Vue. Set

The above two methods can be implemented quickly, but for new properties,Vue provides a new method,Vue. Set, to solve the problem that new properties do not trigger data response

/** * target Specifies the object to be modified * prpertyName Specifies the name of the property to be added * value Specifies the value of the property */
Vue.set( target, propertyName, value )
Copy the code

The above requirement can be changed to using vue.set

import Vue from 'vue'

// Add the user's official account here
handleAddOfficialAccount() {
  Vue.set(this.userInfo,'officialAccount'.'Interesting front end')}Copy the code

But every time we need to use the set method, we have to introduce Vue, so for simplicity, Vue mounts the set method to the Vue prototype chain, This is vue.prototype. set= vue.set, so you can use this.set = directly inside the Vue component Set = this. Set = this. Set = this. Set = this. This.$set(this.userInfo,’officialAccount’, ‘the front end is interesting ‘)

Many developers don’t know when to use Vue. Set. In fact, you only need to use Vue and set if the property you want to assign has not been defined.

4. Use the $forceUpdate

I think forceUpdate makes a lot of front-end developers stop paying attention to bidirectional binding, because whenever I change data, I call forceUpdate, it makes a lot of front-end developers stop paying attention to bidirectional binding, because whenever I change data, Anyway, after I change the data, I call forceUpdate, so that a lot of front-end developers will not pay attention to the bidirectional binding of data, because whenever I change the data, I call forceUpdate and the Vue component will render again, the bug will not exist. In practice, however, this approach is not recommended, as it can cause many unnecessary performance costs. The specific approach to arrays is not only for objects, but also for arrays that do not respond to changes in data, such as this code

<template>
  <div>
    <ul>
      <li v-for="item in list" :key="item">
        {{ item }}
      </li>
    </ul>
    <button @click="handleChangeName">Modify the name</button>
  </div>
</template>
<script>
export default {
  data() {
    return {
      list: ['Ming'.'xiao li']}},methods: {
    // Modify the user name
    handleChangeName() {
      this.list[0] = 'wang'}}}</script>
Copy the code

The above code wants to change xiaoming’s name to Xiaowang, but this change does not actually work because Vue cannot detect the following array changes:

When you set an item directly using an index, such as this.list[index] = newValue, you modify the length attribute of the array, such as this.list.length = 0Copy the code

So in the example above by enclosing a list [0] = ‘wang’ cannot be trigger data response, what should do? Vue. Set (this.list,0,’ xiao Wang ‘)

In addition to those methods, Vue also provides mutating methods for arrays

When we manipulate an array, we use many of the data provided methods, such as push,pop,splice, and so on. When we change the value of the array, we invoke these methods in Vue to trigger the data response. This.list.splice (0,1,’ xiao wang ‘)

In fact, if Vue only relies on getters and setters, it is impossible to trigger the data response when the array calls push,pop and other methods, so Vue actually hijacks these methods, and packs and mutates them to achieve this. Vue wrapper variation on the following methods of an array:

push
pop
shift
unshift
splice
sort
reverse
Copy the code

So when you operate on an array, call the above methods to ensure that the data can respond normally. Here is the code for wrapping the array method in Vue source code:

var original = arrayProto[method];
  def(arrayMethods, method, function mutator () {
    // Convert arguments to an array
    var args = [], len = arguments.length;
    while ( len-- ) args[ len ] = arguments[ len ];
    var result = original.apply(this, args);
    // This is the same as dependArray(value) to get the DEP
    var ob = this.__ob__;
    var inserted;
    switch (method) {
      case 'push':
      case 'unshift':
        inserted = args;
        break
      case 'splice':
        inserted = args.slice(2);
        break
    }
    // If there is new data inserted, then the inserted data also needs a response
    if (inserted) { ob.observeArray(inserted); }
   // Notify the dependency to update
    ob.dep.notify();
    return result
  });
Copy the code

If you use vUE process with good implementation of new data binding response can be learned in the comments below this blog ~