Search code examples
reactjsmaterial-uiautosuggesttsxreact-tsx

react-autosuggest with debounce and distinctUntilChanged


Intent:

I'm trying to achieve an ideal search field that will not make any API calls untill:

  1. The debounce time of 350ms has been reached
  2. AND until there's a change in the value of the input field.

What I've tried so far:

I've used a Subject to track for changes in the input field. Every time there's a change in the input field and handleSuggestionsFetchRequested is called, I'm pushing a new value down the Subject using searchString$.next(userInput);

And in the useEffect hook, I'm pipeing the searchString$ with debounceTime(350) and distinctUntilChanged(). Something like this:

useEffect(() => {
  searchString$
  .pipe(
    debounceTime(350),
    distinctUntilChanged(),
    switchMap(searchString =>
      ajax(`https://api.github.com/search/users?q=${searchString}`)
    ),
    map((networkResponse: any) => networkResponse.response.items)
  )
  .subscribe((suggestions: Array<User>) => setSuggestions(suggestions));
}, [searchString$]);

But the API calls are still going everytime there's a change in the userInput.

The Issue:

I think the issue is that every time the value of the input field changes, I'm setting the state as well:

const handleChange = (
  event: React.ChangeEvent<{}>,
  { newValue }: Autosuggest.ChangeEvent
) => {
  setUserInput(newValue);
};

This is causing the Component to re-render and calling the useEffect, which is eventually making the API call again and again.

I could be wrong.

How to replicate:

I've created a Sample Code Sandbox that replicates the issue.

Thanks a lot in advance.


Solution

  • Thanks to the comments from yurzui on my tweet, I was able to figure out the reason for the issue.

    I was creating a new Subject on every reconciliation as the line:

    const searchString$: Subject<string> = new Subject<string>();
    

    was right inside my component function.

    I moved it out and it was working like a charm.

    NOTE: As suggested by yurzui, don't forget to catch errors in the ajax call otherwise the Subject will die.

    I've updated the Code Sandbox Sample, just in case somebody needs to refer to it.