【问题标题】:Rxjs and React state hooks causing multiple API calls and re-rendersRxjs 和 React 状态钩子导致多个 API 调用和重新渲染
【发布时间】:2020-08-01 15:54:38
【问题描述】:

我正在尝试在 React 中实现一个使用 RxJs 的简单搜索框。设计很简单,向api发出请求的主要逻辑如下:


export class SeachService {
  constructor() {
    this.searchTerm = new Subject();
  }

  search(term) {
    this.searchTerm.next(term.value);
  }

  doSearch(term) {
    let promise = api.business.searchByCompany(term);

    return Observable.fromPromise(promise);
  }

  getResults() {
    return this.searchTerm
      .debounceTime(300)
      .distinctUntilChanged()
      .switchMap((term) => (term ? this.doSearch(term) : Observable.of([])))
      .map((response) => {
        return {
          details: response,
          result_hash: Date.now(),
        };
      })
      .distinctUntilChanged((a, b) => a.result_hash === b.result_hash)
      .catch((error) => {
        console.error(error);
        return Observable.of([]);
      });
  }
}

我在 React 组件中使用它:

 useLayoutEffect(() => {
    const subscription = searchService
      .getResults()
      .subscribe((res) => setBusinessResults(res.details));
  });

但是,这会导致对 API 进行多次 ajax 调用,就好像组件会重新渲染多次一样。当我使用简单的console.log(res.details) 时,我得到了预期的行为,即只进行一次调用并相应地进行限制。有没有办法解决这个问题?

【问题讨论】:

  • 为什么要使用 Date.Now() 检查不同的调用?那将永远不同。你应该使用 term 而不是 no?

标签: reactjs rxjs


【解决方案1】:

您可以在此处处理多个 API 调用。只有当用户的输入有 2 秒的间隔时,您的 API 才会调用。

  /**
   * Handle Timeouts
   */
  timeouts = {
    term_name: null,
  };

  /**
   * Search Term
   *
   * @param {String} name
   */
  searchTerm = name => {
    if (this.timeouts.term_name) {
      clearTimeout(this.timeouts.term_name);
    }

    this.timeouts.term_name = setTimeout(() => {
      this.searchTerm(); // Here you can call api it will trigger only if user has a gap of 2 seconds in his input
    }, 2000);
  };

【讨论】:

    【解决方案2】:

    在 useLayoutEffect 钩子上添加空的依赖数组来模拟组件确实挂载的生命周期。还记得在卸载组件时取消订阅 observable,以避免再次安装组件时多次订阅。组件确实卸载了生命周期,可以模拟在 useLayoutEffect 挂钩中返回一个函数:

    useLayoutEffect(() => {
        const subscription = searchService
          .getResults()
          .subscribe((res) => setBusinessResults(res.details));
    
        return () => subscription.unsubscribe();
    }, []);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-12-01
      • 2021-11-11
      • 1970-01-01
      • 2021-02-21
      • 2019-08-30
      • 1970-01-01
      • 2020-06-27
      相关资源
      最近更新 更多