Angular9 公共组件封装之三级组件通信

RT

一、需求

image

  1. 白色区域为公共组件A;
  2. 红色区域为公共组件B,有色绿色区域为多个功能按钮(如年、月、日)
  3. 黑色区域为组件C(可以看做是一个页面)
  • 组件C用于想服务端拉取数据,再向组件B传递,并且在页面中复用组件B(多次)
  • 组件A用于展示数据
  • 组件B中的绿色按钮部分用于触发重新拉取数据

二、我的解决方案

  1. 使用@Input和@Output逐层通信,C拉取数据传递给A,B触发点击事件后通过EventEmitter传递给A,在A中再通过EventEmitter传递给C,C接收后再向服务端拉取数据,再把获取的数据传递给A,用作展示
  2. 新建一个service,在service中定义一个subject,再定义两个方法sendMsggetMsg用于发布订阅,在C中注入service,调用getMsg方法用于订阅消息,在A中注入service,调用sendMsg方法用于发布消息

三、思考

  1. 第一种解决方案,个人觉得这样不够友好,且传递次数过多,而且写法也比较low
  2. 第二种解决方案,使用rxjs,感觉高大上了很多,但不易阅读。并且当在C组件多次复用A的时候,依然要使用第一种解决方案去向每一个复用的A组件传递一个唯一标识name,然后A再将name传递给B,当B触发点击事件的时候再把这个唯一标识name传递回C,用于确定再次获取数据后给哪个被复用的A更新数据。这样就很绕

四、问题

  1. 有没有其他解决方案?
  2. 如果没有,在原有的解决方案中如何能更优雅?
阅读 3.6k
5 个回答

既然已经写成组件了,angular 就只有@input和@output来传递信息了。

多级组件双向通讯一般用service,如果只是共享数据,直接用service的属性就可以,如果需要互相通知,可以用subject,这是标准的做法。

@input和@output是父子组件通讯的基本机制,但层数多了就不好用了。

service还可以实现同级组件之间通讯,甚至没有什么关系的组件之间的通讯。

子组件可以直接依赖注入其上级的组件

<component-a>
    <component-b></component-b>
</component-a>
export class ComponentB {
    constructor(private componentA: ComponentA) {
    }
}

自上而下的数据管理方式避免不了这种一级一级的消息传递。解决方案就是类似 redux 的这种统一的中心式状态管理方案。

题目中的问题根源在于只有最顶层的 C 有资格去服务器拉数据,所以动作要一层层冒上去,然后再更新数据,再把数据一层层分发下来。

中心式的状态管理的思想是,把动作和数据抽离到一个中心去管理,动作会改变数据,数据改变后会通知订阅者。各组件大家无论层级高低,都可以订阅自己感兴趣的数据,都可以触发恰当的动作。

所以简单的实现,你可以用一个 service 来抽象这个状态管理器,配合 rxjs 不难实现。

项目很大层级很深的,可以考虑 ngrx ,基本就是 redux + rxjs,配合 Angular 的依赖注入,个人感觉比 react + redux 还好用一些。

感觉已有的解决方案都能解决当前的问题。
要说是否有改善的地方,不知道这样行不:

dataSubject = new Subject<?>();

/**
* 该方法由组件B来触发
**/
reoload() {
    this.loadData().subscribe((data) => {
        this.dataSubject.next(data);
    });
}

/**
* 该方法由组件C触发
*/
loadDataAndAutoRefresh():Oberserver {
    this.reload();
    return this.dataSubject.asOberserver();
}

private loadData():Oberserver {
    return this.httpClient.xxx();
}
撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题