How to make an asynchronous return a promise chain within render() with componentDidMount()?

Viewed 77

I have a button within my return in my render function that calls a function that initiates a promise chain which the result updates a state variable. However, the value is not passed through.

I tried some attempts on componentDidMount() but haven't had any luck

Here is the button within my render function

<button onClick={this.addIPFSItem} className="btn btn-info btn-sm m-1">NewFile</button>

This calls the following function

addIPFSItem(){

var searchAddress = "0x9Cf0dc46F259542A966032c01DD30B8D1c310e05";

const contract = require('truffle-contract')
const simpleStorage = contract(SimpleStorageContract)
simpleStorage.setProvider(this.state.web3.currentProvider)


this.state.web3.eth.getAccounts((error, accounts) => {
  simpleStorage.deployed().then((instance) => {
    this.simpleStorageInstance = instance

    return this.simpleStorageInstance.getLength(searchAddress);
  }).then((accountLength) => {

    var items = []
    const ipfsPrefix = "https://ipfs.io/ipfs/";

    var i;
    for (i = 0; i < accountLength; i++) {
      var currHash = this.simpleStorageInstance.getBook(searchAddress, i, 
  {from: searchAddress});

      var currURL = ipfsPrefix + this.currHash;

      //Here I am printing the counter values, and it prints the correct 
      //amount
      console.log('itemhash ', i)
      items.push(currHash)
    }
    //I do not get the value of items[1] in the console, but an undefined
    //promise
    console.log('address URL ', items[1])

    //the state of ipfsHash is not updated correctly
    return this.setState({ipfsHash: items[1]});
  })
 })
}

Essentially, I am executing a promise chain (by connecting to web3) and retrieving data. I think the essential problem is that I am calling an async function within the render(). I'm not sure how to fix this with componentDidMount()

console.log('address URL ', items[1]) should give something like address URL 0x9Cf0dc46F259542A966032c01DD30B8D1c310e05. However, I instead get address URL Promise{<pending>}.

1 Answers

Your this.simpleStorageInstance.getBook is a promise, that means it is executed asynchronously.

To get it's result you either have to use .then or the new syntax async/await. With the following function your items array will be filled with the correct data :

You will have to put the async keyword before your parent function name if you choose this solution

for (i = 0; i < accountLength; i++) {
    items.push(await this.simpleStorageInstance.getBook(searchAddress, i, { from: searchAddress }))
}

An even shorter syntax would imply using your raw array of accounts and map it instead of using its length :

const items = myAccounts.map(async () => await this.simpleStorageInstance.getBook(searchAddress, i, { from: searchAddress }))
Related