Ardalan
Ardalan

Reputation: 849

react select load async options does not load

I want to load options from backend. So i have to fetch data from API and then update options. But i don't know how to do it. Can someone help? Here's my code:

function myComponent() {

  const loadOptions = () => {
    console.log('on load options function')
    axios.get(`/api/admin/roles`)
      .then((response) => {
        const options = []
        response.data.permissions.forEach((permission) => {
          options.push({
            label: permission.name,
            value: permission.id
          })
        })
        return options
      })
  }

  return ( 
    <AsyncSelect 
      isMulti 
      cacheOptions 
      loadOptions={loadOptions}
    />
  )
}

By the way nothing gets logged at all and that means the loadOptions function does not run. Here's my response from API:

response: {
  data: {
    permissions: [{
      id: 13,
      name: 'deposit'
    }, {
      id: 14,
      name: 'withdraw'
    }]
  }
}

Upvotes: 4

Views: 4862

Answers (4)

Seth
Seth

Reputation: 10454

The issue you're experiencing seems to be due to the fact that you're not returning anything at the top-level of the loadOptions function.

The documentation highlights two ways to define your loadOptions function.

Using callbacks:

const loadOptions = (inputValue, callback) => {
  setTimeout(() => {
    callback(options);
  }, 1000);
};

Using promises:

const loadOptions = inputValue =>
  new Promise(resolve => {
    setTimeout(() => {
      resolve(options);
    }, 1000);
  });

In your case, it might be simplest to try the callback option first since your existing syntax is conducive with it.

const loadOptions = (inputValue, callback) => {
  console.log('on load options function')
  axios.get(`/api/admin/roles`)
    .then((response) => {
      const options = []
      response.data.permissions.forEach((permission) => {
        options.push({
          label: permission.name,
          value: permission.id
        })
      })
      callback(options);
    })
}

In the future you can optionally leverage the inputValues parameter to down-filter results.

Upvotes: 4

Zia ur Rehman
Zia ur Rehman

Reputation: 565

Try this

const loadOptions = async () => {
    const response = await axios.get(`/api/admin/roles`)
    const result = await response.data
    return await result.permissions.map((permission) => ({
      label: permission.name,
      value: permission.id
    }))
  }

Upvotes: 0

Shubham Khatri
Shubham Khatri

Reputation: 281626

Your loadOptions function must return a promise. Also you can pass defaultOptions as true to make the request fire for initial set of options

const loadOptions = () => {
    console.log('on load options function')
    return axios.get(`/api/admin/roles`)
      .then((response) => {
        const options = []
        response.data.permissions.forEach((permission) => {
          options.push({
            label: permission.name,
            value: permission.id
          })
        })
        return options
      })
  }

function myComponent() {
  return ( 
    <AsyncSelect 
      isMulti 
      cacheOptions 
      defaultOptions
      loadOptions={loadOptions}
    />
  )
}

P.S For performance reasons, you can declare your loadOptions function outside of the component so that it doesn't get recreated on every re-render

Upvotes: 2

samuei
samuei

Reputation: 2102

AsyncSelect expects a defaultOptions prop, which you have not provided. The docs are unclear about what behavior it should exhibit in this case, but I'd guess it defaults to loading on filter.

Upvotes: 0

Related Questions