K. Peters
K. Peters

Reputation: 195

React Bootstrap Typeahead AsyncTypehead synchronous issue with Redux

I am developing a user search feature in my react/redux application using react-bootstrap-typehead: http://ericgio.github.io/react-bootstrap-typeahead/

The user search calls an API to search the list of users, so I am using the AsyncTypeahead component.

Since I are using Redux, I am storing the loading and search results within the store, so my code looks something like this:

const { searchPeople, loading, searchResults, selectedPerson } = this.props;
          <AsyncTypeahead
            isLoading={loading}
            options={searchResults}
            labelKey="DisplayName"
            clearButton
            minLength={5}
            onSearch={searchPeople}
            onChange={handleChange}
            placeholder="Search for a user..."
            renderMenuItemChildren={option => (
              <TypeaheadItem key={option.EmployeeID} item={option} {...this.props} />
            )}
          />

The onSearch={searchPeople} calls an action in Redux to call the API and store the results in "searchResults":

const searchPeople = term => async dispatch => {
  dispatch({
    type: REQUEST_SENT
  });

  const results = await dispatch(applicationActions.peopleSearch(term));

  dispatch({
    type: REQUEST_RECEIVED,
    data: results
  });
};

My "peopleSearch" function is stored in another action where I have all of our user search functionality. That is why I am dispatching to another action.

const peopleSearch = searchTerm => async () => {
  const url = `https://api-personSearch.test.com/search=${searchTerm}&Output=JSONP`;
  const response = await fetchJsonp(url);
  const data = await response.json();
  return data.slice(0, 10);
};

Everything works perfectly if I search for a user typing slowly. The problem is, if I type a users name quickly or at a normal pace, multiple "REQUEST_SENT" dispatches get called before any "REQUEST_RECEIVED" get called. So looking at the Redux Dev Tools shows results looking like this:

REQUEST_SENT
REQUEST_SENT
REQUEST_SENT
REQUEST_RECEIVED
REQUEST_RECEIVED
REQUEST_RECEIVED

What ends up getting sent to the interface does not end up being the results for the last letter the user ended up typing.

What would be the proper way to use AsyncTypeahead with Redux so that the results are returned in the proper order that they are sent?

Not Great Solution

One thing that ended up working (even though I think it's sort of a hack) is adding a "delay" to the AsyncTypehead. Adding a delay={1000} prop to the AsyncTypeahead component gives the api just enough time to finish it's call before another call to the api is made.

I would like to find a better solution if one is possible.

Upvotes: 5

Views: 2212

Answers (2)

taylor michels
taylor michels

Reputation: 528

I think it's a bug in the component where AsyncContainer and TypeheadContainer get out of sync. The delay approach works most of the time but even then I could type it in a way that I would get no results. Not happy with this answer either but turning off the cache is the only way to guarantee that doesn't happen.

useCache={false}

Upvotes: 0

David Harkness
David Harkness

Reputation: 36542

I'm having a different issue in my usage, but I can suggest a solution to the ordering problem.

  1. Store the last query string in Redux.
  2. When a request completes, ignore it if it isn't for the last query string.

Ideally, you'd cancel the previous request when receiving a new one in onSearch(), but this will have the same effect. If the user keeps typing, delaying long enough for onSearch() to be fired but quick enough to cause overlapping requests, only the last request will display results.

Upvotes: 1

Related Questions