Search code examples
reactjsautosuggestreact-apollo

Apollo client and type ahead


Currently i have an apollo client that has a textbox that will fill an autocomplete via typeahead format. I am using react-autosuggest to fill the suggestions.

In my code i have a HOC, also i trigger a refetch and set the variable on the textboxes onChange.

const TypeAheadWithData = graphql(TypeAheadQuery, {
  options: ({ name }) => ({ variables: { name } })
})(TypeAhead);
export default TypeAheadWithData;

currently i have two issues. One when i type the info the updated results do not get fetched and instead if shows the prior typeahead result. FOR eg If i have a string that is 'san' and i add 'sand' it will show the results of the 'san' query. When i refetch on the data, I am unable to wait async for the data. Essentially trying to figure out how to wait for the refetch async. Or some other form of this. Obsservable/Watch Query maybe. Any guidance in this regard would help greatly.

function getSuggestionValue(suggestion) {
  return suggestion.name;
}

function renderSuggestion(suggestion) {
  return (
    <span>{suggestion.name}</span>
  );
}
class TypeAhead extends React.Component {
  constructor() {
    super();

    this.state = {
      value: '',
      suggestions: [],
      isLoading: false
    };
  }

  componentWillReceiveProps() {
    this.setState({
      suggestions: this.props.data.characters
    });
  }

  onChange = (event, { newValue }) => {
    console.log(newValue);
    //this.props.data.variables.name = newValue;
    this.props.data.refetch({name: newValue});
    this.setState({
      value: newValue
    });
  };

  shouldRenderSuggestions(value) {
    return value.trim().length > 2;
  }

  onSuggestionsFetchRequested = ({ value }) => {
    //this.props.data.refetch({});
    // this.setState({
    //   suggestions: this.props.data.characters
    // });
    // this.loadSuggestions(value);
  };

  onSuggestionsClearRequested = () => {
    this.setState({
      suggestions: []
    });
  };

  render() {
    const { value, suggestions, isLoading } = this.state;
    const inputProps = {
      placeholder: "Type 'c'",
      value,
      onChange: this.onChange
    };
    const status = (isLoading ? 'Loading...' : 'Type to load suggestions');

    return (
      <div>
        <div className="status">
          <strong>Status:</strong> {status}
        </div>
        <Autosuggest
          suggestions={suggestions}
          onSuggestionsFetchRequested={this.onSuggestionsFetchRequested}
          onSuggestionsClearRequested={this.onSuggestionsClearRequested}
          getSuggestionValue={getSuggestionValue}
          renderSuggestion={renderSuggestion}
          shouldRenderSuggestions={this.shouldRenderSuggestions}
          inputProps={inputProps} />
      </div>
    );
  }
}

const TypeAheadWithData = graphql(TypeAheadQuery, {
  options: ({ name }) => ({ variables: { name } })
})(TypeAhead);
export default TypeAheadWithData;

The main issue i am having is that the previously loaded list of suggestions is being suggested. As it is not waiting for the refetch and it is not updating the state at all when a new set of them is being received.


Solution

  • There's no need to utilize the component's state if you are already receiving the suggestions as props from Apollo. I would change your initial state to:

    this.state = {
      value: '',
      isLoading: false
    };
    

    Then you can just get your suggestions inside render like this:

    const suggestions = this.props.characters || []
    

    Looking at the docs for react-autosuggest, I would also move the refetch call into onSuggestionsFetchRequested. I imagine utilizing onChange like you are should also work, but this covers more potential scenarios where we would want to get the suggestions again.

    onSuggestionsFetchRequested = ({ value }) => {
      this.props.data.refetch({name: value});
    };