Source:  Twitter logo

I'm using react and react-select and trying getting options from the api. Everything work on me but I want to show loading text into react-select while data coming from the api.

Here is my react-select component:

<Select
    onChange={this.getSelectedOption}
    onFocus={this.getData}
    options={options}
    value={selectedOption}
    styles={customStyles}
    placeholder="Select...."
/>

and here in onFocus I make api call via redux action and set the state with response which coming from redux reducer.

  getAvailableDisplays() {
    this.props.getData(); /// redux action dispatch
    if (this.props.data.items) {
   this.setState({ this.state.options: this.props.data.items }); }
  }

With this way everything work but while request finish there is text no options..

I saw here something https://react-select.com/async but I can't understand where make api call.

Or how can I just write loading in select while api call finished and state filled

You have a few options here for loading options asynchronously from an HTTP request.

Just a note: if you need your options in the Redux store, you can get your options in your component using Redux mapStateToProps, no need to set them in component state. If you don't need them in the store, using a Redux action and reducer is unnecessary since you can just execute your HTTP/axios request directly from your component and set the result in your component state. Examples provided assuming you want to do this using redux.

Check out this sandbox for working examples of the below components (wrapper simulating Redux actions and mapStateToProps): https://codesandbox.io/s/trusting-golick-wx991?file=/src/Selects.js

If you are set on loading on focus, using AsyncSelect won't help you since it only provides builtin options to load on render or on input change. If you want to show the loading message in the dropdown, you can do so by setting the options to default to a single option with the loading message in the label and disabling the dropdown depending on loading state. You can also use loading state to set the loading message in the input box, instead of/in addition to in the dropdown, if desired:

const MySelect = props => {
  const [loading, setLoading] = useState(false);
  const [hasLoaded, setHasLoaded] = useState(false);

  const handleFocus = () => {
    if (!props.options && !hasLoaded) {
      setLoading(true);
      setHasLoaded(true);
      return props.getData().then(() => setLoading(false));
    }
  };

  return (
    <Select
      onFocus={handleFocus}
      options={props.options || [{ value: 0, label: "Loading..." }]}
      placeholder={loading ? "Loading options..." : "Select...."}
      isDisabled={loading}
    />
  );
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

However, if you aren't actually set on loading the options on focus, AsyncSelect will let you very easily load the options either when the component renders or when the input is changed (typing in the select box), and by default it will show "Loading..." text in the dropdown if it's open while options are still loading:

const MyAsyncSelect = props => {
  return (
    <AsyncSelect
      loadOptions={props.getAsyncData} // function that executes HTTP request and returns array of options
      placeholder={"Select...."}
      defaultOptions // load on render
      // defaultOptions={[id: 0, label: "Loading..."]} // uncomment this and comment out the line above to load on input change
    />
  );
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

If you want the loading message in the input box as well as/instead of the dropdown for AsyncSelect, you can accomplish this using loading state as well:

const MyAsyncSelectLoading = props => {
  const [loading, setLoading] = useState(false);

  const getData = () => {
    return props.getAsyncData().then(result => {
      setLoading(false);
      return result;
    });
  };

  return (<AsyncSelect
    loadOptions = {getData}
    placeholder = {loading ? "Loading data" : "Select...."}
    defaultOptions
    // isDisabled={loading} // uncomment this to disable dropdown until options loaded
  />);
};
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/16.6.3/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/16.6.3/umd/react-dom.production.min.js"></script>

Also - the above getAvailableDisplays function wouldn't work, because you're calling asynchronous getData, then checking this.props.data.items before the asynchronous action has had time to complete.

5 users liked answer #0dislike answer #05
shannon profile pic
shannon

Copyright © 2022 QueryThreads

All content on Query Threads is licensed under the Creative Commons Attribution-ShareAlike 3.0 license (CC BY-SA 3.0).