Lightning Web Components – How to Share Asynchronous JS File Object Value to LWC JS File

javascriptlightning-web-componentslwc-wire-adapter

I have created a LWC where I am making callout using Fetch API. Callout is working as expected when I use single JS file.
Now, I want to split my logic in JS into sub JS file as we can create Multiple JS file in LWC.

LWC Component Name : testLwcComp

In TestLwcComp.js:

import { LightningElement } from "lwc";
import { fetchData } from "./fetchData"; //calling fetchData JS file
export default class TestLwcComp extends LightningElement {
    @wire(getRecord, {
        recordId: "$recordId",
        fields: [someFields]
    })
    wireInfo({ error, data }) {
        if (error) {
        } else if (data) {
            let info = fetchData();
            console.log("info:" + info);
        }
    }
}

fetchData.JS(added in same LWC testLwcComp):

let information={};
export function fetchData(){
        fetch(endpoint)
        .then(response=>response.json())
        .then(data=>{
            console.log(data)
            information= {
             a: data.a,
             b:data.b,
             c:data.c
            }
        })
        .catch(error=>console.error(error));
        return information;
    }

Now in info console log of TestLwcComp.js, I am getting value as Undefined and then fetchData.JS gets executed since it has Asynchronous callout.

To control the sequence I am trying to use async await here:

let info = async =>{
let data;
data = await fetchData();
return data;
}

but It's still not working.

Can someone please tell me how can I fetch the value in info debug logs? What I am doing wrong here?

Instead of Fetch API call, If I try to return some value(synchronous execution), I can retrieve value in info console log.

Best Answer

You need to slightly tweak your code. In the utils file, declare the function as async and await the fetch call.

export default async function fetchData(url = '', params = {}) {
    const response = await fetch(url);

    if (!response.ok) {
        throw Error(response.statusText);
    }
    return response.json();
}

and in your code, you can either use async/await or use promise-based invocation.

async makeCallout(){
    try{
        let response = await fetchData('http://www.google.com');
        console.log(response);
    } catch(e){
        // handle error
    }

    // or use a promise based invocation

    fetchData('http://www.google.com').then((data)=>{
        // do something
    }).catch((err) => {
        // handle error
    });
}

I have implemented a similar pattern in this file.

However, a small suggestion based on your code snippet - Looks like you're making a callout after the data is provisioned using a wire service. I would recommend moving the callout logic also to Apex, and use a single wire call to get both the data from Salesforce and the API as well.. Making API calls from JS exposes secrets like Auth Tokens that you may send, and also you may run into CORS issues.

Related Topic