I will give you a detailed analysis of the relevant knowledge and problem solving methods of props passing parameters in vue.js. Friends in need can refer to it.
This article uses demo examples to give you a detailed analysis of the usage of parameters passed by props and solutions to problems encountered. The following is the full content.
Some time ago, vue was used to build a backend management system, in which each page required a table to display information. Naturally, I thought of extracting the table and making it into a public component, and passing in the data from different pages for rendering to achieve the purpose of reuse.
demo address
1. Problem discovery
In the parent component, the data that needs to be passed to the table component is a table The content data tableData, the page data page of the table.
TableData is an Array object, which is an array composed of all data objects that need to be displayed in the table. And pageInfo is an Object object, which contains table page information. Initialize the two data pairs in the parent component as follows, in the form
tableData:[], pageInfo: { current: 1, // 当前是第几页 total: 100, // 数据对象的总数 size: 20 // 每页显示的数量 }
According to the instructions in the official documentation, prop is one-way binding and prop should not be changed inside the child component. The reason why I want to modify the data in prop is mainly because after prop is passed in as the initial value, the sub-component wants to use it as local data. For this situation, the official statement is to define a local variable and initialize it with the value of prop:
props: ['tableData', 'pageInfo'], data() { return { tData: this.tableData, page: this.pageInfo } }
Then according to the official documentation, all props of the child component will be updated every time the parent component is updated. is the latest value. The information of tableData and pageInfo is obtained asynchronously from the server through the api:
{ error: 0, msg: "调用成功.", data: { restrictioninfo: [...], total: 42 } }
Therefore, when the data is obtained, the parent component needs to change the value passed into the child component:
me.tableData = Json.data.restrictioninfo; me.pageInfo.total = Json.data.total;
It stands to reason At this time, the value in the subcomponent should be updated to the value returned by the server, but the total number of subcomponent pages has been updated, but the table data is still the empty array during initialization. (Black question mark???)
.
2. Assignment and Binding
First I need to locate where the data went wrong, so I made a demo to locate it. question.
First look at the initial values of each element in the parent component and child component:
Then when only the reference to the array in the parent component is changed, you can see the child The props array of the component changes accordingly, but the array bound in the sub-component does not change accordingly
Therefore, it can be found that the problem lies in this step
props: ['tableData', 'pageInfo'], data() { return { tData: this.tableData, page: this.pageInfo } }
To figure out the root cause of the problem, you have to figure out the in-depth responsiveness principles in the vue document.
"In the data option of the Vue instance, Vue will traverse all the properties of this object and use Object.defineProperty to convert all these properties into getters/setters"," Each component instance has a corresponding watcher instance object, which records the properties as dependencies during component rendering. Later, when the dependency's setter is called, the watcher will be notified to recalculate, causing its associated components to be updated. ." The document says a lot. The simple understanding is that Vue bidirectionally binds vm.$data.a in the data option and vm.a in the DOM, that is, if one of them changes, the other will also change. . In the Vue source code, it is implemented by the defineReactive$$1 function:
But in the sub-section, the get and set methods of Object.defineProperty are mainly used to achieve two-way binding. In the sub-component, the pros data and the $data of the sub-component are connected in the following way:
tData: this.tableData
Querying the Vue source code shows that there is only an assignment between this.tableData and tData, that is, the "=" relationship
The above initData function is executed when the component is built, so it will only be executed once during create. This is why the official document says "pass in as initial value", because it will only be executed once. When the component is built, there is no relationship between this.tableData and tData. Changes in one will not cause changes in the other. Of course, this statement is not accurate, because in the above, we dynamically change the total passed in by the parent component, and the child components also change "concurrently". It feels like they are bound together. What's going on? Woolen cloth?
3. Illusions caused by reference types
Of course, we still have to start from the official documents to solve this problem. There is such a tip in the documentation:
这里就需要理解引用类型的概念,引用数据类型值指保存在堆内存中的对象。也就是,变量中保存的实际上的只是一个指针,这个指针指向内存中的另一个位置,该位置保存着对象。访问方式是按引用访问。例如一个js对象a,他在内存中的存储形式如下图所示:
var a = new Object();
当操作时,需要先从栈中读取内存地址,然后再延指针找到保存在堆内存中的值再操作。
a.name = 'xz';
引用类型变量赋值,本质上赋值的是存储在栈中的指针,将指针复制到栈中未新变量分配的空间中,而这个指针副本和原指针指向存储在堆中的同一个对象;赋值操作结束后,两个变量实际上将引用同一个对象。因此,在使用时,改变其中的一个变量的值,将影响另一个变量。
var b = a;
在了解了引用类型之后,我们在来看看上文提到的动态改变传入子组件前后内存中的情况:
me.tableData = Json.data.restrictioninfo; me.pageInfo.total = Json.data.total; ======================================== props: ['tableData', 'pageInfo'], data() { return { tData: this.tableData, page: this.pageInfo } }
首先对tableData的改变是改变了其引用的指针,而对pageInfo则改变了其中一个属性的值,因此动态改变前:
动态改变后:
这样就解释了为什么子组件页面的总数更新了,但table数据依然是初始化时的空数组。因为引用类型的存在,我们动态改变父组件传入的total,子组件也"随之"改变了。
上面是我整理给大家的,希望今后会对大家有帮助。
相关文章:
The above is the detailed content of Detailed explanation of how props pass parameters in vue.js. For more information, please follow other related articles on the PHP Chinese website!