javascript - 使用 RXJS 进行搜索输入,该输入进行 API 调用,但订阅会重复发生,即使使用 debounceTime

标签 javascript angular typescript rxjs

我有一个 html 搜索输入框,它连接到我的组件文件中的 ViewChild。

<input #userSearch type="text" placeholder="Search by Name or Email...">
@ViewChild('userSearch', {static: false}) set userSearch(input: ElementRef|null) {
        if (!input) return;
        this.setInput(input);
    }

public setInput(input) {
        fromEvent(input.nativeElement, 'keyup')
            .pipe(
                auditTime(1000),
                map((event:any) => {
                    return event.target.value;
                }),
                debounceTime(1000),
                distinctUntilChanged(),
            )
            .subscribe((text: string) => {
                this.count++
                console.log("count ++ is", this.count)
                this.searchTerm = text;
                console.log("this.searchTerm", this.searchTerm)
                if (this.searchTerm.length > 2) {
                    this._loadUsers({
                        search_name_or_email: this.searchTerm
                    });
                } else {
                    this._loadUsers();
                }
            });

    }

在我的 setInput 函数中,我使用 debounceTime 和auditTime,目的是当用户完成输入时,该搜索词将被发送以进行 api 调用。

问题是,当我输入搜索词“Ron”时,我的 console.log 返回 count++ 为 1。当我删除我的搜索词时,该订阅会被触发多次,所以现在我的计数接近 8。当我输入新的搜索词时,计数会被触发到 15。每次我删除并添加新的搜索词时,订阅 block 被重复触发,这意味着 this._loadUsers 中的 api 调用被重复调用,这是一个问题。

我不明白为什么我的订阅 block 被调用了这么多次。我的理解是,使用 debounceTime 时,当用户完成输入时,在 debounceTime 解析后,就会触发订阅 block 。但由于某种原因,当用户完成输入时,订阅 block 会呈指数级触发?

更新:感谢您查看此内容。我删除了auditTime,但它仍然引起问题。我已将问题调试到构造函数中的此 setter 方法。我不熟悉这个 ViewChild setter 方法,但从一些文档中我发现 https://blog.angularindepth.com/beware-angular-can-steal-your-time-41fe589483df (第 #2 点),当 ref 输入元素嵌套在 *ngIf 内时必须使用。由于某种原因,这个 setter 方法在编辑搜索查询时会多次触发,我不确定为什么,因为我对 ViewChild 的 setter 方法不熟悉。


export class UsersComponent implements OnInit {
    @ViewChild('userSearch', {static: false}) set userSearch(input: ElementRef|null) {
        if (!input) return;
        this.count++
        console.log("count ++ is", this.count)
        this.setInput(input);
    }

最佳答案

使用主题而不是 fromEvent,如果您以这种方式销毁并重新创建搜索框,则只需创建一个可重用的可观察链,而不是每次都重新创建。按照您的方式,每次隐藏输入时,您都需要从旧链取消订阅。您有仍订阅该输入的孤立订阅。

<input type="text" placeholder="Search by Name or Email..." (keyup)="search($event.target.value)">

以及在 TypeScript 中

search$ = new Subject();

search(val) {
  this.search$.next(val);
}

ngOnInit() {
    this.search$
        .pipe(
            auditTime(1000),
            map((event:any) => {
                return event.target.value;
            }),
            debounceTime(1000),
            distinctUntilChanged(),
        )
        .subscribe((text: string) => {
            this.count++
            console.log("count ++ is", this.count)
            this.searchTerm = text;
            console.log("this.searchTerm", this.searchTerm)
            if (this.searchTerm.length > 2) {
                this._loadUsers({
                    search_name_or_email: this.searchTerm
                });
            } else {
                this._loadUsers();
            }
        });
 }

关于javascript - 使用 RXJS 进行搜索输入,该输入进行 API 调用,但订阅会重复发生,即使使用 debounceTime,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/58019099/

相关文章:

javascript - Centos服务器中的Nodemailer,电子邮件发送但不接收

javascript - 等待事件发生时返回 promise 的函数

angular - observer.error()之后需要调用observer.complete()?

angular - RxJS 可观察。一旦我有引用,如何重新发射

javascript - Ionic2 + Angular2 - 试图分配给只读属性

javascript - react & typescript : Property 'id' does not exist on type 'number'

javascript - Chrome 的加载指示器在 XMLHttpRequest 期间不断旋转

javascript - 保持无序列表对齐

Angular:如何将字符串发送到注入(inject)服务?

javascript - 是否有/什么是在 Angular 应用程序中查询所有 `img` 标签的最佳方法?