1. Why can’t the view update the render after updating the data?
Users of Vue will inevitably encounter such a “pit”
Why can’t THE view render when I update the data?
For example
<! -- Using vue-cli scaffolding -->
<template>
<div>
<button @click="change"</button>
<button @click="add"> Add object attributes </button>
<div v-for="(val, key) in obj" :key="key">
{{ val }}
</div>
</div>
</template>
<script>
export default {
data () {
return {
obj: {
a: '1'.
b: '2'.
c: '3'
}
}
},
methods: {
change () {
this.obj.a = '0'
},
add () {
this.obj.d = '4'
}
}
}
</script>
Copy the code
When I click the “Change Object Properties” button, the view is updated
Instead, I click the add Object Properties button, and the view doesn’t update
Before opening the vue-devTools tool
We can see that the data has been updated!
Only the view is not updated!
So why is that?
In fact, this is the responsivity principle of the Vue involved
In Vue2. X, the reactive core API is Object.defineProperty
The following with a section of JS code, simulation vUE responsive source code
// Define an empty object
const propsObj = {}
// Define the listener
const obj = {
a: '1'.
b: '2'.
c: '3'
}
// Simulate update view
const updateView = (key, oldVal, newVal) => {
Console. log(' View updated ~ ')
The console. The log (` key values${key}Update from${oldVal}Update to the${newVal} `)
}
// define listener responsive methods
const defineReactive = (target, key, value) => {
/ / core API
Object.defineProperty(target, key, {
get() {
return value
},
set(newValue) {
updateView(key, value, newValue)
value = newValue
}
})
}
// Iterate over the setup listener
for (const key of Object.keys(obj)) {
defineReactive(propsObj, key, obj[key])
}
// Update data
propsObj.a = '0'// Trigger response
propsObj.d = '4'// Add object attributes without triggering responsiveness
Delete propsobj. a // Deletes object properties without triggering reactive type
Copy the code
Output result:
visible
If you want to trigger reactive updates
You want to make sure that the properties of the object trigger the response
In the first example, the “Add Object Properties” button is clicked and the view is not updated
Because he’s adding an attribute to the object
Of course! Also note that the delete operation cannot trigger responsiveness either!
To sum up:
“1. Make sure that the object property changed is an existing property of the object to listen to the response“
“2. When you add or delete object attributes, you cannot listen in response mode“
In fact, it is clearly stated on the official website of Vue
Arrays are much the same
The “small difference” of arrays is that:
Vue overrides these array methods so that they can trigger view updates
2. The solution?
① Use vue. set/vue. delete
Use Vue’s API specifically for this type of problem
<! -- Using vue-cli scaffolding -->
<template>
<div>
<button @click="change"</button>
<button @click="add"> Add object attributes </button>
<div v-for="(val, key) in obj" :key="key">
{{ val }}
</div>
</div>
</template>
<script>
export default {
data () {
return {
obj: {
a: '1'.
b: '2'.
c: '3'
}
}
},
methods: {
change () {
this.obj.a = '0'
},
add () {
// Add object methods
this.$set(this.obj, 'd'.'4')
}
}
}
</script>
Copy the code
Of course, delete is also similar, not to repeat
Note the Vue version: 2.20+
(2) use the vm. $forceUpdate
Use force update views
<! -- Using vue-cli scaffolding -->
<template>
<div>
<button @click="change"</button>
<button @click="add"> Add object attributes </button>
<div v-for="(val, key) in obj" :key="key">
{{ val }}
</div>
</div>
</template>
<script>
export default {
data () {
return {
obj: {
a: '1'.
b: '2'.
c: '3'
}
}
},
methods: {
change () {
this.obj.a = '0'
},
add () {
this.obj.d = '4'
// Force an update to the view
this.$forceUpdate(a)
}
}
}
</script>
Copy the code
③ Use deep copy and reassign to replace
For objects, deep copy can use json.parse (json.stringify (obj))
As long as the change object is not the same object
Because we’re reassigning, it shouldn’t be the same object
That’s how reactive is triggered
For example
<! -- Using vue-cli scaffolding -->
<template>
<div>
<button @click="change"</button>
<button @click="add"> Add object attributes </button>
<div v-for="(val, key) in obj" :key="key">
{{ val }}
</div>
</div>
</template>
<script>
export default {
data () {
return {
obj: {
a: '1'.
b: '2'.
c: '3'
}
}
},
methods: {
change () {
this.obj.a = '0'
},
add () {
// Const obj = this.obj is not available
// Reason: They are identical and refer to the same object
/ / conso namely; e.log(obj === this.obj) //true
// Make a deep copy of the object using sequence, deserialization, and reassign it
const obj = JSON.parse(JSON.stringify(this.obj))
obj.d = '4'
this.obj = obj
}
}
}
</script>
Copy the code
For arrays, you can use methods like slice, concat, and so on
Thank you for reading