Coding With Fun
Home Docker Django Node.js Articles Python pip guide FAQ Policy

7 situations where Vue data is updated but the page is not updated, and you've encountered several


May 31, 2021 Article blog


Table of contents


The article comes from the public number: Pixel Swing, author Leiy

1. Vue was unable to detect property that did not exist in data when the instance was created

Cause: Because Vue performs a getter/setter conversion on property when the instance is initialized, property must exist on the data object in order for Vue to convert it to responsive.

scenario:

var vm = new Vue({
  data:{},
  // 页面不会变化
  template: '<div>{{message}}</div>'
})
vm.message = 'Hello!' // `vm.message` 不是响应式的

Solution:

var vm = new Vue({
  data: {
    // 声明 a、b 为一个空值字符串
    message: '',
  },
  template: '<div>{{ message }}</div>'
})
vm.message = 'Hello!'

2. Vue cannot detect the addition or removal of object property

Cause: Official - Due to JavaScript (ES5) restrictions, Vue .js cannot detect the addition or deletion of object properties. Because Vue .js converts the property to getter/setter when the instance is initialized, the property must be on the data object before Vue .js convert it to make it responsive.

scenario:

var vm = new Vue({
  data:{
    obj: {
      id: 001
    }
  },
  // 页面不会变化
  template: '<div>{{ obj.message }}</div>'
})


vm.obj.message = 'hello' // 不是响应式的
delete vm.obj.id       // 不是响应式的

Solution:

// 动态添加 - Vue.set
Vue.set(vm.obj, propertyName, newValue)


// 动态添加 - vm.$set
vm.$set(vm.obj, propertyName, newValue)


// 动态添加多个
// 代替 Object.assign(this.obj, { a: 1, b: 2 })
this.obj = Object.assign({}, this.obj, { a: 1, b: 2 })


// 动态移除 - Vue.delete
Vue.delete(vm.obj, propertyName)


// 动态移除 - vm.$delete
vm.$delete(vm.obj, propertyName)

3. Vue cannot detect the direct modification of an array item through an array index

Cause: Official - Due to JavaScript limitations, Vue cannot detect changes in arrays and objects;

scenario:

var vm = new Vue({
  data: {
    items: ['a', 'b', 'c']
  }
})
vm.items[1] = 'x' // 不是响应性的

Solution:

// Vue.set
Vue.set(vm.items, indexOfItem, newValue)


// vm.$set
vm.$set(vm.items, indexOfItem, newValue)


// Array.prototype.splice
vm.items.splice(indexOfItem, 1, newValue)

Expansion: Object.defineProperty() monitors array changes

Object.defineProperty() monitors array changes. However, the addition of an index to the array does not monitor for data changes because the subscript (index) of the new array cannot be monitored, as does deleting a property (index).

scenario:

var arr = [1, 2, 3, 4]
arr.forEach(function(item, index) {
    Object.defineProperty(arr, index, {
    set: function(value) {
      console.log('触发 setter')
      item = value
    },
    get: function() {
      console.log('触发 getter')
      return item
    }
  })
})
arr[1] = '123'  // 触发 setter
arr[1]          // 触发 getter 返回值为 "123"
arr[5] = 5      // 不会触发 setter 和 getter

4. Vue cannot monitor changes in the length of an array that is directly modified

Cause: Official - Due to JavaScript limitations, Vue cannot detect changes in arrays and objects;

scenario:

var vm = new Vue({
  data: {
    items: ['a', 'b', 'c']
  }
})
vm.items.length = 2 // 不是响应性的

Solution:

vm.items.splice(newLength)

5. The operation of the DOM data does not change until the asynchronous update is performed

Cause: Vue was asynchronous when updating the DOM. A s soon as you hear data changes, Vue opens a queue and buffers all data changes that occur in the same event loop. I f the same watcher is triggered more than once, it is pushed into the queue only once. T his removal of duplicate data when buffering is important to avoid unnecessary calculations and DOM operations. T hen, in the next event loop, tick, Vue refreshes the queue and performs the actual (de-heavy) work. Vue attempts to use native Promise.then MutationObserver and setImmediate for asynchronous queues, and if the execution environment does not support it, it takes setTimeout(fn, 0)

scenario:

<div id="example">{{message}}</div>
var vm = new Vue({
  el: '#example',
  data: {
    message: '123'
  }
})
vm.message = 'new message' // 更改数据
vm.$el.textContent === 'new message' // false
vm.$el.style.color = 'red' // 页面没有变化

Solution:

var vm = new Vue({
  el: '#example',
  data: {
    message: '123'
  }
})
vm.message = 'new message' // 更改数据
//使用 Vue.nextTick(callback) callback 将在 DOM 更新完成后被调用
Vue.nextTick(function () {
  vm.$el.textContent === 'new message' // true
  vm.$el.style.color = 'red' // 文字颜色变成红色
})

Expansion: Misunderstanding of data responses caused by asynchronous updates

<!-- 页面显示:我更新啦! -->
<div id="example">{{message.text}}</div>
var vm = new Vue({
  el: '#example',
  data: {
    message: {},
  }
})
vm.$nextTick(function () {
  this.message = {}
  this.message.text = '我更新啦!'
})

In the previous section of code, we declared a message empty object in the data object, and then executed the following two pieces of code in the asynchronous callback triggered after the end of the next DOM update cycle:

this.message = {};
this.message.text = '我更新啦!'

Here, the template is updated, the page will finally show 我更新啦!

The template has been updated and should be responsive, so if you think so, you're already in the wrong place.

At first we just declared a message empty object in the data object and didn't have a text property, so the text property is not responsive.

But the template has actually been updated, and what's going on?

That's because Vue .js's DOM update is asynchronous, that is, when the setter operation occurs, the instruction is not immediately updated, the instruction update operation will have a delay, when the instruction update is actually executed, the text property has been assigned, so the instruction update template gets a new value.

Each instruction/data binding in the template has a corresponding watcher object that records properties as dependencies during calculations. Then, when the dependent setter is called, the watcher is triggered to recalculate, which causes its associated instructions to update the DOM.

The process is as follows:

  • Execute this.message = {}; when setter is called.
  • Vue .js trace to message setter is called, triggering a watcher recalculation.
  • this.message.text = '我更新啦!'; The text property is assigned.
  • When the asynchronous callback logic execution is complete, it causes its associated instructions to update the DOM, and the instruction updates to start executing.

So the real trigger for a template update is this.message = {}; This sentence is caused by the trigger setter so look at the above example alone, the data with responsive characteristics is only message layer, its dynamically added properties are not available.

Corresponding to the second point above - Vue cannot detect the addition or removal of object property

6. Loop nesting level is too deep, view is not updated?

See some people on the Internet say that the level of data updates is too deep, resulting in data not being updated or slow updating leading to attempts not to update?

Since I haven't been in this situation, and I've tried to recreate this scenario, I've found that it didn't happen, so don't over-describe it (if someone is in a real situation).

The solution given for the above situation is to use forced updates:

If you find that you need to do a forced update in Vue, 99.9% of the time, you did something wrong somewhere.

vm.$forceUpdate()

7. Expansion: When routing parameters change, the page is not updated (data is not updated)

Extending a problem where the page is not updated because of changes in routing parameters, and the non-update of the page is essentially that the data is not updated.

Cause: When a route view component references the same component, when a route changes, it causes the component to fail to update, which is what we often say is an issue where the page in cannot be updated.

scenario:

<div id="app">
  <ul>
    <li><router-link to="/home/foo">To Foo</router-link></li>    
    <li><router-link to="/home/baz">To Baz</router-link></li>    
    <li><router-link to="/home/bar">To Bar</router-link></li>    
  </ul>    
  <router-view></router-view>
</div>
const Home = {
  template: `<div>{{message}}</div>`,
  data() {
    return {
      message: this.$route.params.name
    }
  }
}


const router = new VueRouter({
  mode:'history',
    routes: [
    {path: '/home', component: Home },
    {path: '/home/:name', component: Home }
  ]
})


new Vue({
  el: '#app',
  router
})

In the previous section of code, we configured a dynamic route '/home/:name' in the routing build option routes which shares a routing component, Home which means that they reuse RouterView

When routing, the page renders only the parameters that the first route matches to, and then route switching, message does not change.

Solution:

There are many ways to solve them, and here are just a few of the methods I use.

  1. Listen for changes $route through watch

    const Home = {
      template: `<div>{{message}}</div>`,
      data() {
        return {
          message: this.$route.params.name
        }
      },
      watch: {
       '$route': function() {
       this.message = this.$route.params.name
        }
        }
    }
    ...
    new Vue({
      el: '#app',
      router
    })

  1. Bind the key property <router-view> so that Vue thinks it's a different <router-view>

Drawback: If we jump from /home to other routes such as /user we don't have to worry about component updates, so this time key property is redundant.

    <div id="app">
      ...
  <router-view :key="key"></router-view>
    </div>

Here are W3Cschool编程狮 seen about Vue data updates but pages that haven't been updated, and you've seen several related introductions that you'd like to help.