【问题标题】:Child prop not updating, even though the parent does子道具没有更新,即使父母更新了
【发布时间】:2018-02-25 15:49:21
【问题描述】:

我有一个非常奇怪的情况,即子组件的 prop 的更改不会触发重新渲染。

这是我的设置。在我的父母中:

        <child :problemProp="proplemPropValue""></child>

在孩子中我定义了道具:

{
    name: "Child",
    props: {
    problemProp: {
        type: [File], //yes it is a file 
        required: true
    }
}

然后我尝试渲染它(仍在子组件中)

<template>
  <div id="dropzone-preview" class="file-row">
    {{problemProp}} <--This should just show the prop as a JSON string-->
  </div>
</template>

这最初是正确呈现的。但是problemProp 有一个属性upload.progress,当我在父级中更改它时(我可以确认它确实在父级上更改)它在子级中没有更改。

如果我现在添加第二个道具,dummyProp 给孩子:

   {
    name: "Child",
    props: {
    problemProp: {
        type: [File], //yes it is a file 
        required: true
    },
    dummyProp: {
        type: Number
    }
}

现在,当dummyProp 发生变化时,propblemProp 也会发生变化。这里发生了什么?为什么dummyProp 的更改会强制重新渲染,而propblemProp 的更改不会?

【问题讨论】:

  • progress 是如何添加到proplemPropValue 的?
  • @Bert 我监听 Dropzonejs 事件并通过 Vuex 商店更新它。 progress 并没有真正“添加”到 proplemPropValue。当proplemPropValue被初始化时,它上面就被progress初始化了。这能回答问题吗?
  • 它是如何更新的?您描述的行为听起来像是代码陷入了更改检测警告(值已更改,但 Vue 不知道它已更改)。
  • 所以子组件实际上是由数组上的v-for 生成的众多组件之一。每次数组中的一项更改时,我都会使用arr.splice(indexOfItem,1, newValue) 更新数组。这种变化会反映在 Vuex 存储和父级中,但不会反映在子级中。
  • 没有代码真的帮不上忙。理想情况下是一个演示问题的工作示例。

标签: javascript vue.js vuejs2 vue-component


【解决方案1】:

问题的根源似乎是当您将 File 对象添加到数组时,Vue 无法将其转换为观察值。这是因为Vue ignores browser API objects:

对象必须是普通对象:浏览器 API 对象等原生对象 并且原型属性被忽略。

在这种情况下,对该对象的任何更改都不会自动反映在 Vue 中(正如您通常所期望的那样),因为 Vue 不知道它们已更改。这也是为什么当您更新 dummyProp 时它似乎可以工作的原因,因为该属性的更改被观察到并触发重新渲染。

那么,该怎么办。通过对 addedFile 方法进行一些小改动,我已经能够让您的垃圾箱工作。

addedfile(file){
  console.log(file);
  self.problemPropValues.push(Object.assign({}, file));
},

首先,您不需要(或不想)使用$data,直接引用该属性即可。其次,通过使用Object.assign 进行复制,Vue 可以正确地观察对象并且更新现在反映在子对象中。 可能在某些情况下您需要使用深拷贝方法而不是 Object.assign,具体取决于您的用例,但目前这似乎可行。

Here is the code我最终让 bin 工作(转换为 codepen,因为我发现使用 codepen 更容易)。

【讨论】:

  • 感谢@Bert 的分析。我浏览了 vue.js 观察者源代码,发现如果此条件成立,则为一个值设置观察者:(Array.isArray(value) || isPlainObject(value)),其中isPlainObject 定义为Object.prototype.toString.call(obj) === '[object Object]'。结果是文件Object.prototype.toString.call(file)==='[object File]',因此条件失败。只是要打开一个问题来找出文件被忽略的原因。再次感谢您的帮助。
  • @SelloMkantjwa 我不知道他们是如何检测普通物体的。我已经看到/使用过代码,其中被观察的对象是 javascript 构造函数(或类)的结果,并且运行良好。有趣的是,File 落入了这个裂缝,它作用 像一个对象,但 toString 以不同的方式呈现它。 Vue 确实声明他们更喜欢文档中某个地方的数据的普通对象。
  • 是的。 vuejs.org/v2/api/#data 来自文档:>对象必须是普通的:浏览器 API 对象和原型属性等原生对象将被忽略。经验法则是数据应该只是数据 - 不建议观察具有自身状态行为的对象。
  • @SelloMkantjwa 感谢您提供该链接 :) 我知道它在某个地方。我用您的其他发现更新了答案。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2017-12-28
  • 2020-08-07
  • 2020-09-30
  • 1970-01-01
  • 2018-12-28
  • 2019-04-17
  • 1970-01-01
相关资源
最近更新 更多