gpt4 book ai didi

angular - 最佳从 EventEmitter 事件重新进入 ngZone

转载 作者:太空狗 更新时间:2023-10-29 18:12:28 27 4
gpt4 key购买 nike

有一个组件封装了一些库。为了避免所有该库的事件监听器的变更检测噩梦,该库的范围在 Angular 区域之外:

@Component({ ... })
export class TestComponent {

@Output()
emitter = new EventEmitter<void>();

constructor(private ngZone: NgZone) {}

ngOnInit() {
this.ngZone.runOutsideAngular(() => {
// ...
});
}

}

这一切都非常清楚和普遍。现在让我们添加事件以发出操作:

@Component({ ... })
export class TestComponent {

@Output()
emitter = new EventEmitter<void>();

private lib: Lib;

constructor(private ngZone: NgZone) {}

ngOnInit() {
this.ngZone.runOutsideAngular(() => {
this.lib = new Lib();
});

this.lib.on('click', () => {
this.emitter.emit();
});
}

}

问题是这个发射器不会触发变化检测,因为它是在区域外触发的。那么有可能重新进入该区域:

@Component({ ... })
export class TestComponent {

@Output()
emitter = new EventEmitter<void>();

private lib: Lib;

constructor(private ngZone: NgZone) {}

ngOnInit() {
this.ngZone.runOutsideAngular(() => {
this.lib = new Lib();
});

this.lib.on('click', () => {
this.ngZone.run(() => this.emitter.emit());
});
}

}

最后,我来谈谈这个问题。此 this.ngZone.run 会强制执行更改检测,即使我没有在父组件中监听此事件也是如此:

<test-component></test-component>

这是不需要的,因为我没有订阅那个事件 => 没有什么可检测的。

该问题的解决方案是什么?

对于那些对现实生活中的例子感兴趣的人,问题的来源是here .

最佳答案

请记住,根据定义,发出值的 @Output() 绑定(bind)是父级更改检测的触发器。虽然该绑定(bind)可能没有任何监听器,但在引用该组件的父模板中可能存在逻辑。也许通过 exportAs@ViewChild 查询。因此,如果您发出一个值,您就是在通知父级组件的状态已更改。也许将来 Angular 团队会改变这一点,但这就是目前的工作方式。

如果你想绕过那个 observable 的变化检测,那么不要使用 @Output 装饰器。移除装饰器并通过 exportAs 访问 emtter 属性或在父组件中使用 @ViewChild

了解响应式表单的工作原理。控件指令具有针对不使用 @Output 的更改的公共(public)可观察对象。它们只是公共(public)可观察对象,您可以订阅它们。

因此,如果您想要一个不与变更检测耦合的可观察对象,则只需将其设为公开的可观察对象即可。这只是保持简单。添加逻辑以仅在 @Output 有订阅者时才发出,这会使您稍后阅读源代码时难以理解码件。

话虽如此,这就是我将如何回答您的问题,以便您可以仅在有订阅者时使用 @Output()

@Component({})
export class TestComponent implements OnInit {

private lib: Lib;

constructor(private ngZone: NgZone) {
}

@Output()
public get emitter(): Observable<void> {
return new Observable((subscriber) => {
this.initLib();
this.lib.on('click', () => {
this.ngZone.run(() => {
subscriber.next();
});
});
});
}

ngOnInit() {
this.initLib();
}

private initLib() {
if (!this.lib) {
this.ngZone.runOutsideAngular(() => {
this.lib = new Lib();
});
}
}
}

如果我以后看到这段源码,我会有点疑惑程序员为什么要这么做。它添加了很多额外的逻辑,这些逻辑并不能清楚地解释逻辑正在解决的问题。

关于angular - 最佳从 EventEmitter 事件重新进入 ngZone,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51787972/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com