The following article is from Pixel Sway by Leiy

[](https://mp.weixin.qq.com/s?__biz=MzU2MzM2NzU0NA==&mid=2247488015&idx=1&sn=193de1d72aca195a6ab917ea2833e482&chksm=fc5a 0918cb2d800ecdff4716fac9696d4bef14a162ef0bb6f99407989abcc29309e06ea3f1f0&scene=0&xtrack=1&key=929ff6ea9407a2ec65aea06872 7bd126027e73b5104104580b2dfb8429527ba861e7de0b412fd2419acdb123edca1c0515fd089b199bd6da38321ce0c997be67c00cbd4c6fdcf1e394 ed84c8c8377c2f8d18f5f6e2a90cc7f3bebc2c5b8ca60a6f893965941c77c9345819adcc09d60dff26ae854533bdfb9cab592fcfc0ad44&ascene=1& uin=MjAzMTgzMzgyMg%3D%3D&devicetype=Windows+10&version=6206034e&lang=zh_CN&exportkey=Aa0b2LsKti41eWAzd3yPXOA%3D&pass_tic ket=3LmWA9EbMKM8AZdoPVIlfxir6%2BsiTUprahSyODQ9N5%2FIOyFMimLhenQrS2%2FXtJ4D&wx_header=0&winzoom=1#)

1. Vue cannot detect properties that were not present in data when the instance was created

Reason: Since Vue performs getter/setter conversions on property when initializing the instance, the property must exist on the data object for Vue to convert it to reactive.

Scene:

Template: '<div>{{message}}</div>'})vm.message = 'Hello! '//' vm.message 'is not responsiveCopy the code

Solutions:

Var vm = new Vue({data: {// declare a and b as a null string message: '',}, template: '<div>{{message}}</div>'})vm. Message = 'Hello! 'Copy the code

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

Reason: Official – Due to JavaScript (ES5) limitations, vue.js cannot detect additions or deletions of object attributes. Because vue.js converts a property to a getter/setter when initializing an instance, the property must be on the data object for vue.js to transform it in order for it to be responsive.

Scene:

Var vm = new Vue({data:{obj: {id: 001}}) '<div>{{obj.message}}</div>'})vm.obj.message = 'hello' // Delete vm.obj.id // Not non-responsiveCopy the code

Solutions:

$setvm.$set(vm.obj, propertyName, newValue) $set(vm.obj, propertyName, newValue) $set(vm.obj, propertyName, newValue) Obj = object. assign({}, this.obj, {a: 1, b: 2}) 'this.obj = object. assign({}, this.obj, {a: 1, b: 2})' this.obj = object. assign({}, this.obj, {a: 1, b: $delete(vm.obj, propertyName) $delete(vm.obj, propertyName) $delete(vm.obj, propertyName)Copy the code

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

Reason: Official – Due to JavaScript limitations, Vue cannot detect array and object changes; Especially rain Stream – performance costs are not proportional to the user experience.

Scene:

Var = new vm Vue ({data: {items: [' a ', 'b', 'c']}}) vm. The items [1] = 'x' / / not responsiveCopy the code

Solutions:

// Vue.setVue.set(vm.items, indexOfItem, newValue)// vm.$setvm.$set(vm.items, indexOfItem, newValue)// Array.prototype.splicevm.items.splice(indexOfItem, 1, newValue)
Copy the code

Extension: Object.defineProperty() can detect array changes

Adding an index attribute to an array will not detect data changes, because the index of the new array cannot be detected, nor will deleting an index attribute.

Scene:

var arr = [1, 2, 3, 4]arr.forEach(function(item, index) { Object.defineProperty(arr, index, { set: Function (value) {console.log(' trigger setter') item = value}, get: Function () {console.log(' trigger getter') return item}})})arr[1] = '123' // trigger setterarr[1] // Trigger getter return value is '123' arr[5] Setters and getters are not triggeredCopy the code

4. Vue cannot detect changes in the length of the array directly modified

Reason: Official – Due to JavaScript limitations, Vue cannot detect array and object changes; Especially rain Stream – performance costs are not proportional to the user experience. (Object.defineProperty() can detect changes in data)

Scene:

Var vm = new Vue({data: {items: ['a', 'b', 'c']}})vm.items. Length = 2 // Not responsiveCopy the code

Solutions:

vm.items.splice(newLength)
Copy the code

5. Manipulating DOM data before an asynchronous update is executed does not change

Reason: Vue executes asynchronously when updating the DOM. As long as it listens for data changes, Vue opens a queue and buffers all data changes that occur in the same event loop. If the same watcher is triggered more than once, it will only be pushed into the queue once. This removal of duplicate data while buffering is important to avoid unnecessary computation and DOM manipulation. Then, in the next event loop, “TICK,” Vue refreshes the queue and performs the actual (de-duplicated) work. Vue internally attempts to use native Promise.then, MutationObserver, and setImmediate for asynchronous queues, and setTimeout(fn, 0) instead if the execution environment does not support it.

Scene:

<div id="example">{{message}}</div> var vm = new Vue({ el: '#example', data: { message: Falsevm.$el.textContent === 'new message' // Falsevm.$el.style.color = 'red' // falsevm The page doesn't changeCopy the code

Solutions:

var vm = new Vue({ el: '#example', data: { message: '123'}})vm.message = 'new message' // Change data // Use vue.nexttick (callback) Callback will be called vue.nexttick (function () $el.textContent === 'new message' // true vm.$el.style.color = 'red' // Text color becomes red})Copy the code

Extension: Data response misunderstandings caused by asynchronous updates

<! -- The page says: I update! --><div id="example">{{message.text}}</div> var vm = new Vue({ el: '#example', data: { message: $nextTick(function () {this.message = {} this.message. '})Copy the code

In the previous code, we declared an empty message object in the data object, and then executed the following two pieces of code in the asynchronous callback that was triggered after the next DOM update loop:

this.message = {}; This.message. text = 'I update! 'Copy the code

At this point, the template has been updated, and the page will finally say I have updated! .

If you think that the template is updated and should be responsive, then you have made a mistake.

We initially declared a message empty object in the data object and did not have a text property, so the text property was not responsive.

But the template has actually been updated. What’s going on here?

This is because the DOM update of Vue. Js is asynchronous, that is, the directive does not update immediately after the setter operation occurs, and there is a delay in the instruction update operation. When the directive update is actually performed, the text property is already assigned, so the directive updates the template with a new value.

Each instruction/data binding in the template has a corresponding Watcher object, which records properties as dependencies during computation. Later, when the setter of the dependency is called, watcher recalculation is triggered, which causes its associated instructions to update the DOM.

! [](data:image/gif; base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVQImWNgYGBgAAAABQABh6FO1AAAAABJRU5ErkJggg==)

The specific process is as follows:

  • Execute ‘this.dataObj = {}; Setter is called when.
  • Vue. Js traces that the ‘setter’ on which ‘message’ depends has been called, triggering a ‘watcher’ recalcalculation.
  • `this.message.text = ‘new text’; ‘assigns to the’ text ‘property.
  • After the asynchronous callback logic completes execution, it causes its associated instructions to update the DOM, and the instruction update begins execution.

So the actual action that triggers a template update is this.message = {}; Because setters are triggered, the only layer of data with responsive properties is the message layer, which doesn’t have dynamically added properties.

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

6. The loop nesting level is too deep and the view is not updated?

See some people on the Internet say that the data update level is too deep, causing the data not to update or update slowly, leading to the attempt not to update?

Since I have never encountered this situation, and when I tried to recreate it, it didn’t happen, SO I won’t say much about it (if anyone has ever encountered this in a real situation, leave a comment).

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

If you find yourself needing a forced update in Vue, 99.9% of the time, you’ve done something wrong.

vm.$forceUpdate()
Copy the code

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

Expand a problem that the page does not update because of routing parameter changes. The page does not update essentially means that the data is not updated.

Reason: When a routing view component references the same component, when the route changes, the component cannot be updated, which is often referred to as the page cannot be updated.

Scene:

<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})Copy the code

In the previous code, we configured a dynamic route ‘/home/:name’ in the routes build option. They share the same route component home, which means they reuse the RouterView.

During route switching, the page will render only the parameters matched by the first route, and the message will remain unchanged during route switching.

Solutions:

There are many ways to solve the problem, and here is just one of the ways I often use.

  1. Listen for changes to $route via ‘watch’.

    const Home = { template:

    {{message}}

    , data() { return { message: this.route.params.name } }, watch: { ‘route’: function() { this.message = this.$route.params.name } }}… new Vue({ el: ‘#app’, router})

  2. Bind the key property so that Vue thinks it is different.

Cons: We don’t need to worry about component updates if we jump from /home to /user, so the key property is unnecessary.

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