Angular 中的子父级沟通最佳实践

Posted

技术标签:

【中文标题】Angular 中的子父级沟通最佳实践【英文标题】:child parent communication best practices in Angular 【发布时间】:2019-01-17 01:35:50 【问题描述】:

我正在努力在 Angular 方面做得更好,我想了解孩子与父母之间沟通的最佳实践。我目前想要使用的应用程序是 Angular 6。我知道我可以使用 @ViewChild、@Output 或创建服务在子父组件之间进行通信。有没有其他的沟通方式?如果不是这三个中的哪个更好,为什么?

这是一个简单的例子:

子 HTML

<button (click)="onLinkedClicked();">Click me</button>

儿童 TS

import  Component, OnInit, Input, Output, EventEmitter  from '@angular/core';
.
.
.
export class showcaseMenuComponent implements OnInit 
    @Output() public linkedClicked = new EventEmitter<String>();

    constructor() 

    onLinkedClicked() 
        console.log('on click child');
        this.linkedClicked.emit('collapsed');
    

父 HTML

<showcase-menu #topNavMenu 
               [showBranding]="false"
               [showSearch]= "false"  
               (linkedClicked)="linkToggler($event)">. 
</showcase-menu>

父 TS

.
.
.
 navMenuState: string;
.
.
.
  linkToggler($event) 
    console.log("partent");
    this.navMenuState = $event;
  

【问题讨论】:

使用 rxjs 主题而不是输出 @Chellappan 酷!为什么这个更好?你有一个很好的例子可以让我在孩子和父母之间建立简单的沟通吗? documentation 列出了更多构建通信结构的方法,但如果没有关于您的预期用例的更多信息,我们基本上不可能说哪种方法“更好”。 @Vlad274 我刚刚在问题中添加了一些简单的代码示例 @Chellappan 我在问题中放了一个简单的代码示例 【参考方案1】:

在您展示的情况下,我更喜欢像您一样使用@Output

点击链接不太可能引起广泛关注,因此我认为服务没有意义。

@ViewChild 可以工作,但它会降低组件的可重用性。如果您想在不同的父组件中重用子组件,则必须复制代码。

使用@Output,如果你想在不同的父组件中使用子组件,不需要复制额外的代码,你可以很容易地绑定到@Output事件。

【讨论】:

酷!如果我错了,请纠正我。让我们假设这个例子有一个孙子。如果我想在父组件和孙子组件之间进行通信,我可以在我的代码中做同样的事情,对吗?还是我必须先在孙子和孩子之间沟通,然后再从孩子到父母? @PatricioVargas 您必须通过孩子传递@Output,但出于同样的原因,我仍然会说这很好,然后孩子和孙子都可以更重用。但是,当事情开始变得像这样复杂时,有些人会争辩使用服务。我不认为那是坏的本身。归根结底,它应该是 6 个月后人们最容易理解的东西。我在简单方面犯了错误 - @Output 很容易 - 但这(诚然)只是我的意见 这完全有道理。非常感谢!!【参考方案2】:

您可以在多个组件之间共享数据

创建服务

 import  Injectable  from '@angular/core';
    import Subject from 'rxjs/Subject';    
    @Injectable()
    export class ChildParentService 

     data=new Subject();
      constructor()  

    

例如:https://stackblitz.com/edit/child-to-parent-bntt2h

【讨论】:

【参考方案3】:

显然这取决于你想做什么。

@Input

通过使用@Input,您将参数直接传递给子组件。 此外,您通过将一个组件放入另一个组件来耦合组件。 这种方法既实用又简单。

当您希望确保将子组件集成到共享特定对象的父组件中并且您不必关心同步机制时,这是一种很好的方法。

也就是说,如果你改变了对象的一个​​属性,对象的引用还是一样的,所以更新为父组件和组件。但是,如果您在一个组件中更改对象引用(例如实例化一个新对象或通过远程服务检索一个新对象),另一个组件将无法检测到对象更改,因此您将出现数据错位。

@Output

通过使用@Output,您将向上发出一个事件,因此当您想与父母交流发生了什么事时,这种方法很有用。数据交换是可能的,但不是重点。

重点是发生了某些事情,例如在向导中,您可以有一些步骤,并且每个步骤都可以告知父组件该特定步骤已完成。父母不需要知道发生了什么,只要知道发生了什么,它就可以进入下一步。

@ViewChild

通过使用@ViewChild,您可以将子组件引用到父组件中。

您正在通过混合它们的逻辑来强制父组件具有特定的子组件来工作。

当你想将子组件的某些方法调用到父组件中时,这很有用。

使用向导的例子你可以考虑一下这种情况:

我们有 3 个步骤 第三步完成并向父级发送@Output 事件 父级捕获事件并尝试保存数据 数据保存成功 => 父级告诉最后一步组件显示成功消息 或 数据保存失败 => 父级告诉最后一步组件显示失败消息

服务

通过使用外部服务,您可以将数据集中到一个负责管理和更新数据的外部对象中。

对于可以从远程服务检索数据或可以重新分配数据对象引用的情况,这是一种很好的方法。

此外,通过这种方法,您可以将所有组件彼此分离。他们可以工作而不必担心别人的行为。

一般Subject用于服务通信。

你可以找到doc here

主题 VS @Output

Subject 使用数据驱动的方法。 @Output 使用事件驱动的方法,或者更好的是 Reactive Programming 方法

因此,同时@Output 是您想要传达事件发生的首选方式,Subject 是传达数据已更改的首选方式。

Subject 既是 observable 值的来源,也是 Observable 本身。你可以像订阅任何 Observable 一样订阅 Subject。

这意味着您可以使用Subject 观察特定变量或值(SubjectObserver),它会检测观察到的值变化并发出某种事件。

与此同时,您可以通过订阅主题的事件让许多其他观察者正在观察SubjectSubjectObservable)。

当主题观察值发生变化时,通知所有主题的订阅者。

例如票务应用程序。一位用户加载负责显示空闲剩余位置的组件。他正在考虑选择哪个地方。同时另一个用户买了一张票,所以他的位置现在不可用。第一个用户现在应该看到该位置不可用,因此您需要刷新数据,要求他们访问远程服务(可能使用轮询算法)。当检索到新数据时,您将新数据传递给Subject.next()Subject 检测到观察值已更改,并通知他的所有订阅者该值已更改。显然Subject 将新数据传递给订阅者。

【讨论】:

最后一个问题,什么时候使用 use rxjs subject 而不是 output?或者因为是在服务内部使用,所以我应用服务“规则”【参考方案4】:

在以下情况下使用父子之间的服务通信:

1.您希望将数据从父组件传递到多个子组件。

2.多个子组件具有相同的EventEmitter,会被分派给父组件。

【讨论】:

以上是关于Angular 中的子父级沟通最佳实践的主要内容,如果未能解决你的问题,请参考以下文章

多态性最佳实践

Rails 4+ 最佳实践:删除父项同时保留子项

在 Angular 站点中使用 content-security-policy 的最佳实践是啥?

angular中订阅方法的最佳实践是啥?

在 ReactJs 中,从 redux 存储或从父级到子级将 props 传递给子组件的最佳实践是啥?

前端架构鉴赏01:Angular 架构模式与最佳实践