angular - Angular:使用 NgIf 进行更改检测问题
问题描述
嘿,我创建了一个演示来大规模演示一个问题。
更新:我已经更新了演示,问题出在 ngIf 上!!
这是演示: https ://stackblitz.com/edit/angular-ivy-bac4pe?file=src%2Fapp%2Flist%2Flist.component.ts
这就是问题所在:我们不仅使用指令作为组件行为的扩展,而且还作为组件的外部 API。我们有一个列表组件,它假设通过分页显示列表的当前项目。我们有一个 paginator 指令,他的工作是为组件公开 Pagination Api。我们有一个分页服务,它根据数据和页面大小执行实际的分页(分页方法)。
我发生了一个非常奇怪的行为:有一个 setInterval 就像轮询一样 - 每 5 秒更新一次数据。当我尝试通过指令->服务-> 更新当前项目列表时,即使我调用了 markforCheck ,项目也没有更新,因为我正在使用推送策略来提高性能。我不想调用detectChanges,因为这是一种不好的做法。
当我尝试使用 markForCheck 通过 Service->Component 更新当前项目列表时,一切正常。
如果有人能详细解释这种现象为什么会发生以及如何解决这个问题,我会很高兴。
解决方案
发生的事情是一系列原因。
首先,注意它this.cdr.markForCheck()
不会运行变更检测,而是将其祖先标记为需要运行变更检测。下次更改检测在任何地方运行时,它也会针对那些被标记的组件运行。
第二个也是更重要的是*ngIf
结构。发生更改时*ngIf
将首先通知并执行以下操作:( github )
@Input()
set ngIf(condition: T) {
this._context.$implicit = this._context.ngIf = condition;
this._updateView();
}
// ...
private _updateView() {
if (this._context.$implicit) {
if (!this._thenViewRef) {
this._viewContainer.clear();
this._elseViewRef = null;
if (this._thenTemplateRef) {
this._thenViewRef =
this._viewContainer.createEmbeddedView(this._thenTemplateRef, this._context);
}
}
} else {
if (!this._elseViewRef) {
this._viewContainer.clear();
this._thenViewRef = null;
if (this._elseTemplateRef) {
this._elseViewRef =
this._viewContainer.createEmbeddedView(this._elseTemplateRef, this._context);
}
}
}
}
如你看到的:
this._viewContainer.createEmbeddedView(this._thenTemplateRef, this._context);
这意味着它需要dom并重新生成它!在此过程中,您将丢失要渲染的更改数据。
下次父组件数据发生更改并且其更改检测触发时,还会检查子组件中的更改,因为您通过markForCheck()
上次调用保留了此检查,再次*ngIf
对其容器之前的更改做出反应,因此它获取并用旧数据替换 dom . 就这样继续下去……所以你总是后退一步。
推荐阅读
- javascript - 带有 ScrollView 的 RefreshControl 在每次刷新时向下移动屏幕内容
- linux - 在机器 [x] 上编译的代码在机器 [y] 上运行时出现段错误 - 但为什么?
- amazon-emr - 如何在 EMR Presto 服务上进行线程转储
- python - 仅在文本的选定部分使用正则表达式修改
- python-sphinx - 将 Sphinx 复制到仅在原始命令中未在 rst 中明确引用的安装位置图像?
- python - 异常值:“QuerySet”对象没有属性“密码”
- excel - 在每组天下运行标题
- python - 我想向已经与 python 字典中的值关联的键添加一个新值
- excel - 在 IF 条件不工作的情况下使用 VBA 进行数据验证
- javascript - 我们可以仅在代码行(GAS/JS)中总结并删除一些数组值吗?