Blueprint: Suggest onQueryChange appears to fire twice because callback changes items prop

Created on 28 Sep 2018  路  5Comments  路  Source: palantir/blueprint

Environment

  • __Package version(s)__: core 3.6.1 / select 3.2.0 / react 16.5.2
  • __Browser and OS versions__: mac, chrome latest

Steps to reproduce

the following is a very simple component that uses Suggest to display a list of users returned by a REST endpoint. searchUsersByName makes a simple fetch() as you'd expect.

export class UserNameLookup extends Component {
  state = { results: [] };

  query = async query => {
    const final = query ? query.trim() : "";
    const results = final ? await searchUsersByName(final) : [];
    this.setState({ results });
  };

  itemRenderer = ({ first, last, uuid }, { handleClick }) => (
    <MenuItem
      className={ITEM_CLASS}
      key={uuid}
      text={`${first} ${last}`}
      onClick={handleClick}
    />
  );

  inputValueRenderer = ({ first, last }) => first + " " + last;

  itemSelect = item => {
    if (this.props.onSelect) {
      this.props.onSelect(item);
    }
  };

  render() {
    return (
      <div className={"user-name-lookup"}>
        <Suggest
          items={this.state.results}
          noResults={
            <MenuItem
              className={ITEM_CLASS}
              disabled={true}
              text={"No results."}
            />
          }
          onQueryChange={this.query}
          itemRenderer={this.itemRenderer}
          inputValueRenderer={this.inputValueRenderer}
          onItemSelect={this.itemSelect}
          inputProps={searchProps}
        />
      </div>
    );
  }
}

UserNameLookup.propTypes = {
  onSelect: PropTypes.func
};

Actual behavior

the query() function is called twice for every keystroke, likely because the result of that call changes items

Expected behavior

it should only be called once even though items changes.

Possible solution

im not sure how to make this work the "ergonomic" way, but obviously i tried to keep track of the query string on my own in the callback in order to avoid firing twice, but that seems impossible because this line https://github.com/palantir/blueprint/blob/develop/packages/select/src/components/query-list/queryList.tsx#L183 in setQuery() calls the callback BEFORE setting the internal state

im not sure how im supposed to do an async call in this situation.

EDIT: also just to be clear, the component works perfectly fine. i only realized it was making two calls when looking at the network tab in dev tools.

Most helpful comment

Same here the component fires 2 times instead of 1.

I also think that onQueryChange break the custom inputProps = {{ onChange : fn() }} but i can't find anywhere in docs a mention so maybe it's only in my case.

if you just want to avoid double call you can check if event is not undefined :

 onQueryChange = (query, event) => {
    if (event) {
      console.log('should send only once')
    }
  }

All 5 comments

I've ran into same issue with Select

i only realized it was making two calls when looking at the network tab in dev tools.

@ixtli You can use lodash/debounce function to prevent multiple requests on one keystroke

Same here the component fires 2 times instead of 1.

I also think that onQueryChange break the custom inputProps = {{ onChange : fn() }} but i can't find anywhere in docs a mention so maybe it's only in my case.

if you just want to avoid double call you can check if event is not undefined :

 onQueryChange = (query, event) => {
    if (event) {
      console.log('should send only once')
    }
  }

Look like onActiveItemChange fired also two times for the same reason

We are having the same problem with Suggest, using onQueryChange method gets fired twice per keystroke. We found the problem is related with the way the component behaves in what is supposed to be a controlled input.

By doing

<Suggest 
  query='',
  onQueryChange={(t, e) => { console.log(t, e); }}
  {...otherProps}
>

In here, the input should never be changed. because we are effectively settings its value to a constant.

This is broken, so not exactly a controlled input.

Was this page helpful?
0 / 5 - 0 ratings