下面的代码简单地说明了我试图用两个模型做什么。假设我们有一个Book模型和一个Author模型。首先,我们使用返回类型Books的服务获取一个Observable<Book>列表。然后,我们使用*ngFor迭代每一次,但是我们也希望在书的旁边显示Author,所以在我们的迭代中我们有如下所示的HTML:
<span>{{ getAuthorName(book) | async }}</span>getAuthorName有自己的请求,可以在AuthorService上通过ID获取作者。问题是,当我们在这里返回一个Observable<string>时,浏览器会完全崩溃,因为更改检测会疯狂运行,因为在每个摘要周期上都会返回一个“新的”可观察到的结果,这会导致更改检测再次运行,对吗?
下面的代码可以很容易地放入StackBlitz并复制(我没有链接到它,因为它会炸掉您的浏览器CPU)
<ul>
<li *ngFor="let item of getData() | async">
{{ getOtherData(item.id) | async }}
</li>
</ul>import { Component } from '@angular/core';
import { of } from 'rxjs';
import { filter, map } from 'rxjs/operators';
@Component({
selector: 'my-app',
templateUrl: './app.component.html',
styleUrls: [ './app.component.css' ]
})
export class AppComponent {
name = 'Angular';
getData() {
return of([{
id: 1
},{
id: 2
},{
id: 3
}]);
}
getOtherData(id: number) {
const data = of([{
id: 1,
name: 'Matt'
},{
id: 2,
name: 'Steve'
},{
id: 3,
name: 'Alice'
}]);
return data.pipe(
map(x => x.find(d => d.id == id))
)
}
}显然,这里可以进行一些优化,比如作者的缓存等,但是一般来说,在RXJS的世界中应该如何处理这个场景呢?我知道有处理像秋田和ngrx这样的状态的完整框架,但是如果我不想处理所有这些,只想用原始的rxjs构建我的应用程序呢?这个问题的解决方案是什么?您是否使用其他rxjs操作符来阻止这种情况发生?(我找不到任何帮助它的方法,因为每次都会返回一个新的Obserable )您是否只需要使用视图模型而不是方法?那样的话,eis总是仅仅是对可观察到的事物的一次引用?(例如,BookAuthorViewModel,它有一个$author属性,在我们将视图迭代到单个可观察到的视图之前设置该属性?)
我还没有找到一个“感觉正确”的解决方案,我觉得我不得不使用这些状态管理框架来做这样简单的事情。
发布于 2019-11-20 05:05:01
您不应该在视图中调用方法。如果您有一个返回可观测值的方法,那么每次更改保留检查值时,都会创建一个新的可观测值。
data$ = of([{
id: 1
},{
id: 2
},{
id: 3
}]);
otherData$ = of([{
id: 1,
name: 'Matt'
},{
id: 2,
name: 'Steve'
},{
id: 3,
name: 'Alice'
}]);然后绑定到可观察到的
<li *ngFor="let item of data$ | async">
{{ otherData$ | async | find: item.id }}
</li>把找到的管子
@Pipe({
name: 'find'
})
export class FindPipe implements PipeTransform {
transform(options, id): string {
return options.find(option => option.id === id);
}
}StackBlitz https://stackblitz.com/edit/angular-6vgosc
发布于 2019-11-20 07:06:49
另一种选择是组合服务中的流。
对于每一本书,你都需要作者的名字。在我的示例中,对于每个ToDo,它都会获得用户名。
todos$ = this.http
.get<ToDo[]>(this.todoUrl)
.pipe(catchError(err => throwError("Error occurred")));
todosWithUser$ = this.todos$.pipe(
mergeMap(todos =>
forkJoin(
todos.map(todo =>
this.http.get<User>(`${this.userUrl}/${todo.userId}`).pipe(
map(user =>({
...todo,
usersName: user.name
} as ToDo)
)
)
)
)
)
);https://stackblitz.com/edit/angular-users-todos-deborahk
todos$流获取所有待办事项(或您的示例中的书籍)。
它使用mergeMap映射和合并列表中的每个ToDo。这是自动订阅“内部”可观察到的检索用户。
forkJoin允许我们处理ToDo的数组并为每个数组找到用户。然后将它们重新加入到一个数组中。
最后一个map将usersName属性添加到每个Todo。
https://stackoverflow.com/questions/58946846
复制相似问题