Javascript 父级更新vuejs时未更新子组件

Javascript 父级更新vuejs时未更新子组件,javascript,typescript,vue.js,vuejs2,vue-component,Javascript,Typescript,Vue.js,Vuejs2,Vue Component,我有一个vue实例,它将对象传递给子组件。子组件有一个复选框,单击该复选框时会调用vue实例处理的事件,以更新传递给子组件的父组件上的对象。基于此,我认为这会导致子组件更新相关字段。但是,当我点击复选框时,日期字段并没有像我预期的那样更新。在下图中,当我选中管理名称复选框时,我希望显示当前日期,但没有看到任何日期。我错过了什么 设计 父实例 子组件 更新 我刚刚注意到,在我的子组件中,我使用了managementso和ManagementSODate,而模型具有ManagementReview

我有一个vue实例,它将对象传递给子组件。子组件有一个复选框,单击该复选框时会调用vue实例处理的事件,以更新传递给子组件的父组件上的对象。基于此,我认为这会导致子组件更新相关字段。但是,当我点击复选框时,日期字段并没有像我预期的那样更新。在下图中,当我选中管理名称复选框时,我希望显示当前日期,但没有看到任何日期。我错过了什么

设计

父实例 子组件 更新
我刚刚注意到,在我的子组件中,我使用了
managementso
ManagementSODate
,而模型具有
ManagementReviewerSO
ManagementReviewerSODate
。更改这些修复了我的代码。然而,基于下面的讨论,我有点困惑,为什么将道具放入本地数据是处理这种情况的不正确方法。有人能解释一下吗

当您基于
道具
initEvaluation
透视图
)创建
数据
属性时,它们不再依赖于道具,您只引用数据,就好像它们只是副本,而不是实际收到的道具一样。所以,他们对道具没有反应

因为您似乎没有在组件中更新它们,所以您可以直接引用
道具
,而不是从
道具
创建的
数据

编辑:划掉它,你正在使用
evaluation
上的
v-model
,因此如果你直接引用它们,你会更改道具

因此,一般来说,我会从数据中删除以下内容:

evaluation: this.initEvaluation
// ...
currentCommentSource: this.perspective

直接引用
道具
,并按照文档中的建议,将
v型
替换为
:value
@input

使用道具初始化数据属性没有错。我认为,在这里的许多评论中,最大的困惑是
initEvaluation
是一个对象。在这种情况下,对该对象的任何更改都将反映在使用该对象的任何地方

在所讨论的代码中,父组件中的
evaluation
和子组件中的
evaluation
是相同的对象。对该对象所做的更改将反映在父对象中,Vue方面不会有任何抱怨,因为从技术上讲,您不是在修改对该对象的引用,而是在更改其属性的值

通常,Vue将抛出警告的地方是,如果您将原语值作为属性传递。假设您传递了一个字符串值,然后将该值与
v-model
一起使用。在这种情况下,Vue将抛出一条警告(在开发版本中),指出您正在修改属性。这一警告有两个原因;首先是因为该值不会传播到父级(这可能是意外行为),其次是因为每当父级中的数据发生更改时,它都会覆盖子级中的更改

但是,当对象或数组作为属性传递时,只有在更改对象引用时,Vue才会抱怨。例如,如果要执行此操作,请在代码中执行以下操作:

this.initEvaluation = new Evaluation()
Vue会抱怨您正在对属性进行变异。但是,在代码中,您只是简单地更改了
initEvaluation
的属性,这不会导致警告,还会导致这些值到处都反映出来,因为您到处都在更新相同的对象

其后果之一是,在代码中设置
evaluation:this.initEvaluation
是虚假的。您可以在模板中使用
initEvaluation
,获得与使用
evaluation
相同的结果。同样,这是因为它们是同一个对象。这是路易斯试图解释的一部分。在本案中,路易斯的第一句话有点误导。data函数只调用一次,这意味着使用属性初始化的数据只接收属性值一次。但是,因为
initEvaluation
是一个对象,所以在问题的代码中它实际上并不重要。对象引用永远不会更改,只有属性会更改。如果父项出于某种原因更改引用,则子项中的
评估
将不会使用新引用更新


对于一个对象来说,是否需要在任何地方立即反映更新是有争议的。在许多情况下,您希望控制更新发生的时间。在这些情况下,您可能会执行类似于
evaluation:Object.assign({},this.initEvaluation)
的操作,这会生成
initEvaluation
对象的副本。这样做的好处是,您可以对子组件中的对象进行任意多的更改,而不会将这些更改反映到组件之外。然后,在验证所有更改是否正确后,可以发出这些更改。

不要在数据函数中存储传递的属性,而不是
求值。ReviewerName
只需使用
initEvaluation.ReviewerName
@AndreyKudriavtsev为什么要避免存储传递的属性?在本例中,我正在更改子组件中的[type]SO和[type]SODate字段。如果我不将这些存储在数据中,那么我将更新道具,这将根据文档抛出错误。因为您破坏了该属性的“反应性”。您应该直接在方法和计算属性中使用属性,而不是使用本地数据,就像使用
this.evaluation.ReviewerSODate
使用
this.initEvaluation.ReviewerSODate
一样。你没有损失任何东西,只是把一个变量换成另一个变量。根据我的经验,这似乎不准确。I h
export class Evaluation {
    private _EmployeeName: string;
    private _EmployeeSO: boolean;
    private _EmployeeSODate: Date;
    private _ReviewerName: string;
    private _ReviewerSO: boolean;
    private _ReviewerSODate: Date;
    private _ManagementReviewerName: string;
    private _ManagementReviewerSO: boolean;
    private _ManagementReviewerSODate: Date;

    constructor() {
        this._EmployeeName = "";
        this._EmployeeSO = false;
        this._EmployeeSODate = new Date("01-01-1900");
        this._ReviewerName = "";
        this._ReviewerSO = false;
        this._ReviewerSODate = new Date("01-01-1900");
        this._ManagementReviewerName = "";
        this._ManagementReviewerSO = false;
        this._ManagementReviewerSODate = new Date("01-01-1900");
    }

    get EmployeeName(): string {
        return this._EmployeeName;
    }
    set EmployeeName(employeeName: string) {
        if (this._EmployeeName != employeeName) {
            this._EmployeeName = employeeName;
        }
    }

    get EmployeeSO(): boolean {
        return this._EmployeeSO;
    }
    set EmployeeSO(employeeSO: boolean) {
        if (this._EmployeeSO != employeeSO) {
            this._EmployeeSO = employeeSO;
        }
    }

    get EmployeeSODate(): Date {
        return this._EmployeeSODate;
    }
    set EmployeeSODate(employeeSODate: Date) {
        if (this._EmployeeSODate != employeeSODate) {
            this._EmployeeSODate = employeeSODate;
        }
    }

    get ReviewerName(): string {
        return this._ReviewerName;
    }
    set ReviewerName(reviewerName: string) {
        if (this._ReviewerName != reviewerName) {
            this._ReviewerName = reviewerName;
        }
    }

    get ReviewerSO(): boolean {
        return this._ReviewerSO;
    }
    set ReviewerSO(reviewerSO: boolean) {
        if (this._ReviewerSO != reviewerSO) {
            this._ReviewerSO = reviewerSO;
        }
    }

    get ReviewerSODate(): Date {
        return this._ReviewerSODate;
    }
    set ReviewerSODate(reviewerSODate: Date) {
        if (this._ReviewerSODate != reviewerSODate) {
            this._ReviewerSODate = reviewerSODate;
        }
    }

    get ManagementReviewerName(): string {
        return this._ManagementReviewerName;
    }
    set ManagementReviewerName(managementReviewerName: string) {
        if (this._ManagementReviewerName != managementReviewerName) {
            this._ManagementReviewerName = managementReviewerName;
        }
    }

    get ManagementReviewerSO(): boolean {
        return this._ManagementReviewerSO;
    }
    set ManagementReviewerSO(managementReviewerSO: boolean) {
        if (this._ManagementReviewerSO != managementReviewerSO) {
            this._ManagementReviewerSO = managementReviewerSO;
        }
    }

    get ManagementReviewerSODate(): Date {
        return this._ManagementReviewerSODate;
    }
    set ManagementReviewerSODate(managementReviewerSODate: Date) {
        if (this._ManagementReviewerSODate != managementReviewerSODate) {
            this._ManagementReviewerSODate = managementReviewerSODate;
        }
    }
}
evaluation: this.initEvaluation
// ...
currentCommentSource: this.perspective
this.initEvaluation = new Evaluation()