Daniel Murphy
Daniel Murphy

Reputation: 358

Asynchronous behavior when calling a function from a react component

In a functional react component I have a declared a state variable (with useState) called IsCached. In Contains the following clickable image.

    <img src={imgSource} alt="button images"
        onClick={function()
        {
         var return_value = CachePDF(props.docLink)
         console.log(return_value)
         if (return_value === true){
             SetIsCached(1)    
         }
         else{
             SetIsCached(0)
         }

        }
    }/> 

My goal is that this button will call a function CachePDF and then set the state variable to 1 or 0 based on if that function was successful. Here is my CachePDF function:

export function CachePDF(url) {
    caches.open('favorites').then(function(cache) {
      var updateCache = cache.add(url);
      updateCache.then(function() {
        console.log("article was cached in favorites")
        caches.open("documents").then(function(cache){
            cache.delete(url).then(console.log("article removed from documents cache"))
        })
        return true
        
      }).catch(function (error) {
        console.log("article was not cached in favorites")
        return false
      })
    })
  }

Right now the problem I am having is that the output of console.log(return_value) is undefined, which I believe is happening due to to asynchronous behavior. At first I thought I could return a promise in CachePDF to ensure that the code to change the variable IsCached is not called until the CachePDF function is completed. But from what I understand I would need to define the .then method for the returned promise inside the CachePDF function and therefore that .then method could not access the state variable inside my functional component. So I am somewhat stuck

Upvotes: 0

Views: 144

Answers (2)

Jose Marin
Jose Marin

Reputation: 964

You could use async/await like this:

    <img src={imgSource} alt="button images"
        onClick={async function()
        {
         var return_value = await CachePDF(props.docLink)
         console.log(return_value)
         if (return_value === true){
             SetIsCached(1)    
         }
         else{
             SetIsCached(0)
         }

        }
    }/> 

And you missed a return in the first line of the function CachePDF, And another return before updateCache.then:

export function CachePDF(url) {
    return caches.open('favorites').then(function(cache) {
      var updateCache = cache.add(url);
      return updateCache.then(function() {
        console.log("article was cached in favorites")
        caches.open("documents").then(function(cache){
            cache.delete(url).then(console.log("article removed from documents cache"))
        })
        return true
        
      }).catch(function (error) {
        console.log("article was not cached in favorites")
        return false
      })
    })
  }

Upvotes: 1

Vitalii
Vitalii

Reputation: 2131

CachePDF does not return anything at the moment. It is useful to return the promise chain from it so:

  • results can be used
  • order of execution is controlled
export function CachePDF(url) {
    return caches.open('favorites').then(function(cache) {
      var updateCache = cache.add(url);
      updateCache.then(function() {
        console.log("article was cached in favorites")
        caches.open("documents").then(function(cache){
            cache.delete(url).then(console.log("article removed from documents cache"))
        })
        return true
        
      }).catch(function (error) {
        console.log("article was not cached in favorites")
        return false
      })
    })
  }

When CachePDF returns a promise we can add handlers to it:

    <img src={imgSource} alt="button images"
        onClick={function()
        {
         CachePDF(props.docLink).then(function (return_value) {
             console.log(return_value)
             if (return_value === true){
                 SetIsCached(1)    
             }
             else{
                 SetIsCached(0)
             }
         })
        }
    }/> 

P.S.

Async/await can also be used if you transpile your code or do not require wide browser support. It'll be much easier to read and is very close to your original code (but returning promise from CachePDF is also required in this case):

    <img src={imgSource} alt="button images"
        onClick={async function()
        {
         var return_value = await CachePDF(props.docLink)
         console.log(return_value)
         if (return_value === true){
             SetIsCached(1)    
         }
         else{
             SetIsCached(0)
         }

        }
    }/> 

Upvotes: 1

Related Questions