With the update to Vue3.0, interviewers have a new weapon in their Arsenal. Interviewer: Why did Vue3.0 rewrite the responsive system?
You and ME, what is the interviewer asking, how should I answer, have no idea what is going on; For example, a Proxy directly proxies objects, rather than hijacking the properties of objects. Better array monitoring; This answer is barely qualified
So what’s the answer?
The logic behind the interviewer
Don’t worry, let’s sort out our thoughts first. Sun Tzu’s art of war goes, “Know yourself and know your enemy, and you won’t be in danger of defeat in a hundred battles.” Interview is like a war, so we need to put ourselves in the other’s shoes and think, why is the interviewer asking such a question? What does the interviewer want from this question? What technical points can this question examine? Think about this question, and then come back to yourself, do you have all these skills? To put it bluntly, an interview is like an exam. You need to read and review the question before you can answer it well. Why do many people think that “interview makes the rocket, job turns the screw”? Because there is no empathy, did not think clearly the logic behind the interview questions;
After we think clearly about this logic, what we need to do is to extract technical points, sort out ideas, and make corresponding solutions; Of course, if you have these technical skills then I’m going to try to disassemble the interview question and extract the knowledge from it. For you, it’s all about these things, how much do you know?
Why did Vue3.0 rewrite responsive systems?
Why rewrite? If it was good before, it would be meaningless to rewrite it. Then what problems existed before and how are they solved now? That’s the key;
I wonder how much you know about the Vue2. X responsivity, are you in technical debt? It doesn’t matter, I will help you pay off your debt, first comb the Vue2. X response;
In fact, based on the interview question, there are many technical points behind, the above, is directly related to the current topic, in the actual interview, it is likely to be based on these technical points, in in-depth communication, here will not expand, you can now clarify these questions, even if you earn;
Vue2. X response type
In fact, about this point, in the official Vue documentation, has already been explained, and said very detailed; Official documentation: cn.vuejs.org/v2/guide/re…
When you pass an ordinary JavaScript object into a Vue instance as the data option, Vue iterates through all of the object's properties, And use Object.defineProperty to turn all of these properties into getters/setters. Object.defineproperty is a non-shim feature in ES5, which is why Vue does not support IE8 and earlier browsers. These getters/setters are invisible to the user, but internally they allow Vue to track dependencies and notify changes when the property is accessed and modified. It is important to note that different browsers format getters/setters differently when printing data objects on the console, so it is recommended to install vue-devTools for a more user-friendly interface for examining data. Each component instance corresponds to a Watcher instance, which records "touched" data properties as dependencies during component rendering. Watcher is then notified when the setter for the dependency fires, causing its associated component to be re-rendered.Copy the code
We use an official graphic to tease out the process;
Let’s start with a piece of code
Response principle
Obj in data is a plain JavaScript object that assigns a random number to this.message by clicking on the Click button. This. message refers to the message property of the obj object in data. When the data of Message changes, the content of the H1 tag on the page will change accordingly. This process is responsive. So how does Vue work? First, Vue internally uses Object.defineProperty() to convert every member in Data to a getter/setter; Getters are used to rely on collections, setters are used to distribute updates; The template content is eventually compiled into the render function, where the _v(_s(message)) message is accessed and the getter is triggered for dependency collection, whereas in the click event in code, once the event handler is triggered to execute, Message will be modified, and setters will be triggered to distribute updates;
Although flow manages clear, but total feeling little what, how can ability connect more fully? We use code to simulate the entire implementation process;
DefineProperty mock code
DefineProperty basic usage, just read the manual: developer.mozilla.org/zh-CN/docs/… Let’s look at the code:
<div id="app">
hello
</div>
<script>
// Emulate the data option in Vue
let data = {
msg: 'hello'
}
// Simulate the Vue instance
let vm = {}
// Data hijacking: To intervene when accessing or setting members of a VM
Object.defineProperty(vm, 'msg', {
// enumerable (traversable)
enumerable: true.// configurable (can be deleted using delete, can be redefined via defineProperty)
configurable: true.// Execute when the value is fetched
get () {
console.log('get: ', data.msg)
return data.msg
},
// Execute when set value
set (newValue) {
console.log('set: ', newValue)
if (newValue === data.msg) {
return
}
data.msg = newValue
// Data changes, update the DOM value
document.querySelector('#app').textContent = data.msg
}
})
/ / test
vm.msg = 'Hello World'
console.log(vm.msg)
</script>
Copy the code
You read that right, 36 lines of code with comments, and that’s how Vue2. X works for a responsive implementation; Continue to implement multiple data responsiveness
<body>
<div id="app">
hello
</div>
<script>
// Emulate the data option in Vue
let data = {
msg: 'hello'.count: 10
}
// Simulate the Vue instance
let vm = {}
proxyData(data)
function proxyData(data) {
// Iterate over all properties of the data object
Object.keys(data).forEach(key= > {
// Convert attributes in data to setters/setters for the VM
Object.defineProperty(vm, key, {
enumerable: true.configurable: true,
get () {
console.log('get: ', key, data[key])
return data[key]
},
set (newValue) {
console.log('set: ', key, newValue)
if (newValue === data[key]) {
return
}
data[key] = newValue
// Data changes, update the DOM value
document.querySelector('#app').textContent = data[key]
}
})
})
}
/ / test
vm.msg = 'Hello World'
console.log(vm.msg)
</script>
</body>
Copy the code
The above code just simulates the principle of responsiveness, but Vue in the implementation, certainly not so simple, next, let’s take a look at the source ah…
Vue2 source code interpretation
First find where reactive code is processed:
After looking at the Vue2. X responsive code, let’s go back to the original question: why did Vue3.0 rewrite the responsive system? Why rewrite? If it was fine before, rewriting is meaningless, then what was the problem before, in other words, what was the problem with defineProperty?
Object. DefineProperty problem
In fact, the problem of defineProperty is already mentioned in the handbook of ve2. X; “Ah, many people just don’t read the document” cn.vuejs.org/v2/guide/re… Vue2 and Vue3 are used to implement a small function. The code is the same and the function is of course the same. However, in Vue2 there are bugs, while in Vue3 there are no problems.
Vue2:
<template>
<div class="about">
<h1>This is an about page</h1>
<p v-for="(v, k) in users">
{{ v.names }}
</p>
<button @click="changes">update</button>
</div>
</template>
<script>
export default {
data() {
return {
users: [{id: 1.names: Luffy - "v2" },
{ id: 2.names: "Naruto - v2"},]}; },methods: {
changes() {
// this.users[0] = {id:'0',names:'liuneng'}
// this.users[1].names = 'lnsdsdfg'
this.users[1] = { id: "1".names: "Liu can - v2"}; ,}}};</script>
<style lang="stylus" scoped></style>
Copy the code
Vue3:
<template>
<div class="about">
<h1>This is an about page</h1>
<p v-for="(v, k) in users">
{{ v.names }}
</p>
<button @click="changes">update</button>
</div>
</template>
<script>
export default {
data() {
return {
users: [{id: 1.names: Luffy - "v3" },
{ id: 2.names: "Naruto - v3"},]}; },methods: {
changes() {
// this.users[0] = {id:'0',names:'liuneng'}
// this.users[1].names = 'lnsdsdfg'
this.users[1] = { id: "1".names: "Liu can - v3"}; ,}}};</script>
Copy the code
Its core point is that defineProperty can not well implement the array index monitoring, and in the implementation code of Vue2, there is no better solution to improve this, especially directly abandoned the implementation; In response to this question, THE University of Utah posted a screenshot on Github for you to see.
So, the problem that Vue has not solved so far is clearly solved in Vue3. The question is, how does Vue3 solve it? The previous Vue3 code uses the traditional Options Api to implement the data responsiveness, while the new Composition Api in Vue3 also implements the responsiveness system. Let’s first feel the basic usage of Composition Api
A responsive system for Composition API
Ref responsive
<template> <! Value --><button @click="addNu"> Composition API: {{nu}}</button>
</template>
<script>
/ / into the ref
import {ref} from "vue"
export default {
setup() {
// define ref responsive data
const nu = ref(1);
// Define the function
function addNu(){
nu.value++;
}
// Return the data and methods to be used directly in the template
return{ nu, addNu }; }};</script>
Copy the code
Reactive reactive
<template> <! Value --><button @click="addNu"> Composition API: {{nu}}</button><! Reactive --> reactive --> reactive<h2>{{revData.name}}</h2>
<h3 @click="ageAdd">Age: {{revData. Age}}</h3>
<p v-for="(v,k) in revData.skill"> {{v}} </p>
</template>
<script>
/ / into the ref
import {reactive, ref} from "vue"
export default {
setup() {
// define ref responsive data
const nu = ref(1);
// reactive
const revData = reactive({
name: 'luffy'.age: 22.skill: ['Rubber machine gun'.'Eat the drumsticks'],})function ageAdd(){
revData.age++
}
// Define the function
function addNu(){
nu.value++;
}
// Return the data and methods to be used directly in the template
return{ nu, addNu, revData, ageAdd }; }};</script>
Copy the code
How is the responsivity implemented in Vue3? The key point is the Proxy function;
Implementation Principle of Proxy
Reactive code implemented using Proxy is much simpler than defineProperty because Proxy naturally listens on the whole object without having to listen on the data after traversing, and resolves the problem of array subscripts. Let’s look at some simulated code:
<div id="app">
hello
</div>
<script>
// Emulate the data option in Vue
let data = {
msg: 'hello'.count: 0
}
// Simulate a Vue instance
const vm = new Proxy(data, {
// a function that performs the agent's behavior
// when a member accesses the VM, it executes
get (target, key) {
console.log('get, key: ', key, target[key])
return target[key]
},
// When the vm member is set, it is executed
set (target, key, newValue) {
console.log('set, key: ', key, newValue)
if (target[key] === newValue) {
return
}
target[key] = newValue
document.querySelector('#app').textContent = target[key]
}
})
/ / test
vm.msg = 'Hello World'
console.log(vm.msg)
</script>
Copy the code