I am trying to store the API response in the async/await functions into the response global variable which will be later accessed by App() but I am being prompted with the error shown below the code.
async function getAllTutors() {
try{
const response = await axios.get('API...');
console.log("getAllTutors(): " + JSON.stringify(response.data.body));
return response;
}catch(error) {
return [];
}
}
var response = null;
(async () => {
console.log("Retrieving Tutors");
response = await getAllTutors();
console.log("response (caller) = " + JSON.stringify(response.data.body))
})();
function App() {
...
console.log("HERE: " + JSON.stringify(response.data.body));
const [ data, setTutors ] = useState(employees);
...
I tried logging the values while in both functions and it does seem to output the desired JSON object but, App() still shows response variable to be undefined. I even tried to change App() to be async/await but I am being lead into other errors.
2
Answers
Ok, so
response
is initially null.You’re calling on some functions that are async which are doing some fetching. At some point in time, those functions will finish fetching the data and update
response
to whatever the return from that API is. But JS doesn’t want to wait on anything it doesn’t need to unless you specifically tell it to. So when you get down tofunction App()
, even though that code comes after all the logic above it, it’s being executed immediately after – before the response comes back and updates the ‘global’ variableresponse
.Essentially, you’re calling
response.data.body
beforeresponse
is set to the response from the API, due to the asynchronous nature of JS. Which errors becauseresponse
is null.The pattern you’re implementing is wrong and weird. The response could be stored in state and the API call could be executed in a useEffect, eg:
Or something similar to that structure, with maybe some things changed based on what the API is returning.
The simplest way to achieve this is to store a promise that resolves with the value. Then you can re-use that promise anywhere.
The issue with this approach in React is that it is not reactive; you won’t trigger any re-renders when data changes.
I would recommend using a context instead to wrap any components requiring the data (or wrap your entire app).
For example
You can then wrap any components in the provider, eg
and in those components…
This will ensure the data is only retrieved once when the context is initialised. It can then be shared with any components you want.