Access items within the then of a promise

0

I have this promise that is responsible for assigning an image to the items that I bring from another endpoint, it worked fine until I wanted to pass a title parameter to the getImage function, I had to put the for out of it to iterate and pass it for each item but the issue is that then I can not assign img to items because items do not fit inside the then. I guess you should make a chain of promises or something, some advice?

  getImage (title) {
    var headers = {
      method: 'GET',
      headers: {
        "Api-Key": "xxx",
        "cache-control": "no-cache"
      }
    }
    return new Promise((resolve, reject) => {
    fetch('https://api.unsplash.com/search/photos?query=${title}&order_by=popular&client_id=xxx', headers)
    .then(result => result.json())
    .then(data => {
      var i = getRandomInt(0, data.results.length);
      resolve(data.results[i].urls.small);
    });
  });
}

  getCards (user) {
    var _this =  this;
    fetch(backend+'/getCards/${user.id}')
    .then(result => result.json())
    .then(items => {
    for (var i = 0; i < items.length; i++) {
      this.getImage(items[i].title).then(function(result) {         //aca items es undefined
          items[i].img = result;
        });
      }
      _this.setState({items});
    });
  }
    
asked by Santiago D'Antuoni 31.01.2018 в 16:54
source

2 answers

0

When the promise is resolved, the variable i has already finished iterating and has the value items.length , so you try to assign the property img to an element that does not exist in the array of items.

One solution would be to transform getCards into an asynchronous function:

async getCards(user) {
    var _this = this,
        items = await fetch(backend + '/getCards/${user.id}')
        .then(result => result.json());

    for (var i = 0; i < items.length; i++) {
        items[i].img = await _this.getImage(items[i].title);
    }
    _this.setState({
        items
    });
}

Another less elegant option is to generate an empty array items_with_img and an array of promises, within which the image is brought and assigned to the element:

var items_wth_img=[],
    promise_array = items.map(function(item) {
       return _this.getImage(item.title).then(function(result) {
          item.img = result;
          items_with_img.push(item);
          return item;
       });
    });
return Promise.all(promise_array).then(function() {
   return _this.setState({items_with_img});
});
    
answered by 31.01.2018 / 18:05
source
3

The problem you are discussing is here I understand, that you say that items [i] .img you do not have it available within that then of the promise. That's because you're passing the anonymous function function (result) ... and you do not have the right one inside.

this.getImage(items[i].title).then(function(result) {         //aca items es undefined
          items[i].img = result;
        });
      }

Try or use the arrow function ...

 this.getImage(items[i].title).then((result) => items[i].img = result);

Or make a bind (this) to your anonymous function.

This example follows your same principles. As we see the value of i is incorrect. We get an erroneous exit from INDEX.

function arrayAsync() {
  return new Promise((resolve, reject) => {
    setTimeout(resolve, 5000);
  })
}

function getArray () {
    return new Promise((resolve, reject) => {
      arrayAsync().then(() => {
        resolve([1,2,3,4,5]);
      });
  });
}

function increaseAsync(value) {
  return new Promise((resolve, reject) => {
    setTimeout(() => resolve(++value), 1000);
  });
}

function getInfo() {
  var _this =  this;
  
  getArray()
  .then(items => {
    for (var i = 0; i < items.length; i++) {
      this.increaseAsync(items[i]).then(function(result) {         //aca items es undefined
        console.log("index " + i + "value " + result);
      });
    }
  });
}

getInfo();

Just making the change from var i to let i make everything work correctly. Therefore there is no need to use AWAIT and make your calls synchronous.

function arrayAsync() {
  return new Promise((resolve, reject) => {
    setTimeout(resolve, 5000);
  })
}

function getArray () {
    return new Promise((resolve, reject) => {
      arrayAsync().then(() => {
        resolve([1,2,3,4,5]);
      });
  });
}

function increaseAsync(value) {
  return new Promise((resolve, reject) => {
    setTimeout(() => resolve(++value), 1000);
  });
}

function getInfo() {
  var _this =  this;
  
  getArray()
  .then(items => {
    for (let i = 0; i < items.length; i++) {
      this.increaseAsync(items[i]).then(function(result) {         //aca items es undefined
        console.log("index " + i + "value " + result);
      });
    }
  });
}

getInfo();
    
answered by 31.01.2018 в 17:03