问题描述
当父组件传递子组件的prop为一个对象时,在父组件修改对象,假设新的porp为newObj,旧的prop为oldObj,如果Object.keys(newObj).length > Object.keys(oldObj).length,会将oldObj存在的属性,newObj不存在的属性,赋予newObj。
父组件修改传入子组件的prop,会触发render更新,进而触发pach打补丁,pach代码中有一段是diff函数,会使oldObj的属性附加到newObj的属性中。
导致错误的打包源代码如下
/packages/vue-cli-plugin-uni/packages/mp-vue/dist/mp.runtime.esm.js的文件中
源码如下如下
// patch函数中
// data为newData,mpData为oldData
var diffData = this.$shouldDiffData === false ? data : diff(data, mpData);
// diff函数
function diff(current, pre) {
var result = {};
syncKeys(current, pre);
_diff(current, pre, '', result);
return result
}
// syncKeys函数
function syncKeys(current, pre) {
if (current === pre) { return }
var rootCurrentType = type(current);
var rootPreType = type(pre);
if (rootCurrentType == OBJECTTYPE && rootPreType == OBJECTTYPE) {
if(Object.keys(current).length >= Object.keys(pre).length){
for (var key in pre) {
var currentValue = current[key];
// 如果newObj的keys数量大于oldObj的keys数量,则会将oldObj的属性赋予newObj,并且值为null
if (currentValue === undefined) {
current[key] = null;
} else {
syncKeys(currentValue, pre[key]);
}
}
}
} else if (rootCurrentType == ARRAYTYPE && rootPreType == ARRAYTYPE) {
if (current.length >= pre.length) {
pre.forEach(function (item, index) {
syncKeys(current[index], item);
});
}
}
}
5条答案
按热度按时间sulc1iza1#
有示例工程吗,理论上syncKeys的那处代码不会执行到的,因为执行diff之前,有个前置处理,保证了新旧obj的根属性是一样的
https://github.com/dcloudio/uni-app/blob/dev/packages/vue-cli-plugin-uni/packages/mp-vue/dist/mp.runtime.esm.js#L5640
zkure5ic2#
https://blog.csdn.net/py_boy/article/details/107189409,可以从这个url看到测试例子,当在父组件修改传向子组件的prop时,会触发。我把代码执行过程截图也发给你,只是截取了一部分,在附件中。 工程我也把我的两个测试组件发给你,父组件father.vue,子组件childTry.vue,在附件中…
------------------ 原始邮件 ------------------ 发件人: "fxy060608"<notifications@github.com>; 发送时间: 2020年7月8日(星期三) 上午9:50 收件人: "dcloudio/uni-app"<uni-app@noreply.github.com>; 抄送: "daifayang"<498108281@qq.com>;"Author"<author@noreply.github.com>; 主题: Re: [dcloudio/uni-app] 父组件向子组件传递propbug (#1882) 有示例工程吗,理论上syncKeys的那处代码不会执行到的,因为执行diff之前,有个前置处理,保证了新旧obj的根属性是一样的 https://github.com/dcloudio/uni-app/blob/dev/packages/vue-cli-plugin-uni/packages/mp-vue/dist/mp.runtime.esm.js#L5640 — You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub, or unsubscribe.
pvabu6sv3#
确实有此问题
之所以将已不存在的key赋值为null,是因为差量数据更新需要对该key做删除逻辑
该算法,可以解决大部分情况,你这个应该是要循环config之类的吧,可以自己computed过滤一下null值
目前你文章里提到的this.$shouldDiffData开关,暂未对外暴露,不排除后续可能有调整。
举例:
const oldData = {a:1,b:2}
const newData = {a:1,c:2}
console.log(diff(newData,oldData)) // {c: 2, b: null}
// 其中c:2是新增属性,b:null是删除属性
kmynzznz4#
可以直接在子组件执行this.$shouldDiffData = false,关闭diff算法。能请教下,将已不存在的key赋值为null,是因为差量数据更新对该key做删除逻辑,是指对子组件中的oldData中做删除逻辑吗,如果为了删除逻辑,,能举个正常例子吗?…
------------------ 原始邮件 ------------------ 发件人: "fxy060608"<notifications@github.com>; 发送时间: 2020年7月8日(星期三) 下午2:39 收件人: "dcloudio/uni-app"<uni-app@noreply.github.com>; 抄送: "daifayang"<498108281@qq.com>;"Author"<author@noreply.github.com>; 主题: Re: [dcloudio/uni-app] 父组件向子组件传递propbug (#1882) 确实有此问题 之所以将已不存在的key赋值为null,是因为差量数据更新需要对该key做删除逻辑 该算法,可以解决大部分情况,你这个应该是要循环config之类的吧,可以自己computed过滤一下null值 目前你文章里提到的this.$shouldDiffData开关,暂未对外暴露,不排除后续可能有调整。 举例: const oldData = {a:1,b:2} const newData = {a:1,c:2} console.log(diff(newData,oldData)) // {c: 2, b: null} // 其中c:2是新增属性,b:null是删除属性 — You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub, or unsubscribe.
rqcrx0a65#
1.$shouldDiffData这个不是正式对外的属性,不排除后续调整的可能性
2.比如v-if="config.b" ,不设置null的话,那就会影响v-if判断了,这种情况,要么全量更新config,要么就是差量更新config.b=null