英文:
Angular - Proper way to share reaction between sibling components
问题
标题并不十分解释性,但我找不到更好的方式来表达我的问题。
我正在使用Angular,并且遇到了一些问题。让我以一个示例来说明:
假设我有一个母组件MomComponent
,其中包含多个KidComponent
。
每个KidComponent
都可以由用户调整大小。如果发生这种情况,所有其他孩子也应该被调整大小。
一个孩子组件还应该能够独立存在,没有兄弟姐妹。
这是我的代码:
// mom.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-mom',
templateUrl: './mom.component.html',
})
export class MomComponent {
width: number;
}
<!-- mom.component.html -->
<app-kid [(width)]="width"></app-kid>
<app-kid [(width)]="width"></app-kid>
<app-kid [(width)]="width"></app-kid>
// kid.component.ts
import { Component, Input, Output, EventEmitter } from '@angular/core';
@Component({
selector: 'app-kid',
templateUrl: './kid.component.html',
})
export class KidComponent {
@Input() set width(w: number) {
this._width = w;
this.draw();
}
@Output() widthChange = new EventEmitter<number>();
private _width = 100;
onUserResize(newWidth: number) {
this.widthChange.emit(newWidth);
this._width = newWidth;
this.draw();
}
draw() {
// 绘制代码
}
}
我的问题是,已调整大小的孩子会被绘制两次。首次是因为我在内部调用它,第二次是因为母亲的变量width
将被更新。
我可以更改我的孩子组件如下,以便它只从外部更改中重绘:
// kid.component.ts
export class KidComponent {
// [...]
onUserResize(newWidth: number) {
this.widthChange.emit(newWidth);
// 我删除这两行:
//
// this._width = newWidth;
// this.draw();
}
// [...]
}
但是,我还想能够单独使用我的KidComponent
,而不与其他孩子共享宽度(只是<app-kid></app-kid>
),在这种情况下,上述代码将不起作用。
我目前能想到的唯一解决方案是:
// kid.component.ts
export class KidComponent {
// [...]
onUserResize(newWidth: number) {
this.widthChange.emit(newWidth);
if (!this.widthChange.observers.length) {
// 没有人监听这个事件,我自己重绘
this._width = newWidth;
this.draw();
} else {
// 有人监听我的调整大小,希望他们
// 负责重绘我...
}
}
// [...]
}
但我不太喜欢这种方法,widthChange
发射器上有观察者并不意味着这个观察者将重新绘制KidComponent
。
所以,我的问题是:我是否忽略了更好的方法?
英文:
The title is not very explanatory, but I couldn't find any better way to phrase my problem.
I'm working with angular, and I've been facing a problem a few times now. Let me show it as an example :
Let's say I have a mother component MomComponent
, which contains multiple KidComponent
.
Each KidComponent
can be resized by the user. If that happens, all of the other kids should be resized as well.
A Kid component should also be able to live without siblings.
Here's my code :
// mom.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-mom',
templateUrl: './mom.component.html',
})
export class MomComponent {
width: number;
}
<!-- mom.component.html -->
<app-kid [(width)]="width"></app-kid>
<app-kid [(width)]="width"></app-kid>
<app-kid [(width)]="width"></app-kid>
// kid.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-kid',
templateUrl: './kid.component.html',
})
export class KidComponent {
@Input() set width(w: number) {
this._width = w;
this.draw();
}
@Output() widthChange = new EventEmitter<number>();
private _width = 100;
onUserResize(newWidth: number) {
this.widthChange.emit(newWidth);
this._width = newWidth;
this.draw();
}
draw() {
// Drawing code
}
}
My problem here, is that the kid which has been resized will be drawn 2 times. One first time because I call it internally, and a second time because the mom's variable width
will be updated.
I could change my kid component as follows, so that it's only redrawn from external change :
// kid.component.ts
export class KidComponent {
// [...]
onUserResize(newWidth: number) {
this.widthChange.emit(newWidth);
// I remove these 2 lines:
//
// this._width = newWidth;
// this.draw();
}
// [...]
}
But then, I also want to be able to use my KidComponent
on its own without sharing its width with other kids (just <app-kid></app-kid>
), in which case, the above code wouldn't work.
The only solution that I can think of right now is the following :
// kid.component.ts
export class KidComponent {
// [...]
onUserResize(newWidth: number) {
this.widthChange.emit(newWidth);
if (!this.widthChange.observers.length) {
// No-one is listening to the event, I redraw myself
this._width = newWidth;
this.draw();
} else {
// Someone is listening to my resize, let's hope they
// take care of redrawing me...
}
}
// [...]
}
But I don't really like this approach, the fact that there is an observer on the widthChage
emitter doesn't mean that this observer will redraw the KidComponent
.
So, my question is : Is there a better approach that I'm missing?
Thanks!
答案1
得分: 1
按照我的建议(简单建议):
// kid.component.ts
import { Component, Input, Output, EventEmitter } from '@angular/core';
@Component({
selector: 'app-kid',
templateUrl: './kid.component.html',
})
export class KidComponent {
@Input() set width(w: number) {
if (this._width === w) return;
this._width = w;
this.draw();
}
@Output() widthChange = new EventEmitter<number>();
private _width = 100;
onUserResize(newWidth: number) {
this.width = newWidth;
this.widthChange.emit(newWidth);
}
draw() {
// 绘制代码
}
}
正如Brandon Tylor提到的,您还可以使用服务来在兄弟组件之间进行通信,但我不知道是否会变得复杂,因为您只需要一个属性。
英文:
As suggested in my comment (simple suggestion):
// kid.component.ts
import { Component } from '@angular/core';
@Component({
selector: 'app-kid',
templateUrl: './kid.component.html',
})
export class KidComponent {
@Input() set width(w: number) {
if(this._width === w) return;
this._width = w;
this.draw();
}
@Output() widthChange = new EventEmitter<number>();
private _width = 100;
onUserResize(newWidth: number) {
this.width = newWith;
this.widthChange.emit(newWidth);
}
draw() {
// Drawing code
}
}
As Brandon Tylor mentioned you could also use services for communication between siblings but i don't know if it is not going to get complicated because you just need one property.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论