What could be the reason for my component not getting the asynchronous data?

Currently, I am delving into the intricacies of React and have been following a tutorial that covers creating components, passing props, setting state, and querying an API using useEffect(). Feeling confident in my understanding up to this point, I decided to put my knowledge to the test by attempting to build something on my own.

Let me share with you my App component:

import './App.css';
import CoinList from './components/CoinList/CoinList';
import { useState, useEffect } from 'react';

        
const heldCoins = ['bitcoin', 'ethereum', 'terra-luna']
    const [coins, setCoins] = useState(null)

    async function getCoinData(coinArray) {
        let myCoins = []  // thinking I should use map to create this array
        for await (let coin of coinArray) {
            fetch(`https://api.coingecko.com/api/v3/coins/${coin}`)
                .then(res => res.json())
                .then(data => {
                    const coinData = {
                        coinName: data.id,
                        price: data.market_data.current_price.gbp
                    }
                    myCoins.push(coinData)
                })
        }
        return myCoins
    }

    useEffect(() => {
        getCoinData(heldCoins).then(data => setCoins(data))
    }, [])

    return (
        <>
            {coins && <CoinList type="holding" coins={coins} />}
        </>
    )
}
export default App;

Upon reflection, I can see that my code is somewhat messy with both async functions and .then() being utilized. I also realize that I should probably be utilizing map to create the new array. Nonetheless, I believe that this current setup should work...

The getCoinData function returns a promise which contains an array of data objects. Once this promise resolves, it updates the state using setCoins within the useEffect hook. My expectation is that this action will trigger a re-render and make the data accessible to the CoinList component.

However, I am encountering an issue where an empty array is being passed to CoinList before the API data has had a chance to return.

I find it puzzling that the same process effectively works in the guided tutorial but is failing here. I'm struggling to identify where I may have gone wrong.

Answer №1

I have some doubts about the functionality of your getCoinData function.

    async function getCoinData(coinArray) {
        let myCoins = [];
        for await (let coin of coinArray) { // here coinArray is not an async iterable, so there's almost no wait happening here
            fetch(/*some api/)
                .then(/*some code*/)
                .then(data => {
                    // some code
                    myCoins.push(coinData)
                })
        }
        return myCoins // I don't see how this waits for the fetch to finish
    }

If you look at the comments in the code snippet above, it appears that the return statement occurs before the completion of the fetch request, leading to a potentially empty return value.

An alternative approach could be using Promise.all instead of the somewhat messy for-await-of loop, like this:

async function getCoinData(coinArray) {
  const promisesArray = coinArray.map((coin) =>
    fetch(`https://api.coingecko.com/api/v3/coins/${coin}`)
      .then((res) => res.json())
      .then((data) => {
        const coinData = {
          coinName: data.id,
          price: data.market_data.current_price.gbp,
        };
        return coinData;
      });
  );
  await Promise.all(promisesArray);
  return coinData;
}

This way, each fetch operation is awaited effectively, ensuring that the function does not return prematurely.

Answer №2

Implement promise all to initiate parallel requests

async function retrieveCoinData(coinList) {
  const promises = coinList.map((coin) =>
    fetch(`https://api.coingecko.com/api/v3/coins/${coin}`)
      .then((response) => response.json())
      .then((data) => {
        const coinInfo = {
          name: data.id,
          price: data.market_data.current_price.gbp,
        };
        return coinInfo;
      })
  );
  return Promise.all(promises);
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

React Component paired with SubComponent has encountered an issue with hot reloading, preventing it from properly

I'm experiencing a strange issue with my project involving a simple SubComponent. Whenever I make changes inside that SubComonent, it doesn't hot reload. I'm unsure of what steps to take to resolve this. This is how my components are define ...

Animation on React child component disappears when re-rendered

My React application utilizes Material UI with a component (let's call it DateSelector) as shown below, slightly altered for demonstration purposes. Material UI provides animations for clicks and interactions within its components. An interesting obs ...

Storing a jquery ajax response for faster retrieval in javascript/browser

Is there a way to implement caching for ajax responses in JavaScript or the browser? According to the jquery.ajax documentation: The default behavior is that requests are always issued, but the browser may serve results from its cache. To prevent the ...

Mastering the Material-UI Grid in SPAs: Conquering the Negative Margin Dilemma

While attempting to build a single page application (SPA), I've encountered an issue with using the Grid component from material-ui. Normally, I rely heavily on the Grid, but in this new project, something seems amiss. The current problem is evident ...

Target the <select> element within a <tr> using jQuery selector and apply an empty css style

When looking at this HTML snippet, I am attempting to target the <select> element with id= "g+anything" inside the <tr id='g2'>. <table> <tr id='g1><td> <select id="gm"> <opt ...

Show the ajax response on a separate page

I am looking to showcase the output of an ajax request on a separate page rather than the page where the ajax call originated. The scenario is that I have a membership directory page, and when a user clicks on a member ID cell, an ajax call sends the ID to ...

The animation in Material UI does not smoothly transition with the webkit scrollbar

I've been experimenting with CSS animations in Material UI's sx property to achieve a webkit scrollbar that eases in and out. However, instead of the desired effect, the scrollbar appears and disappears instantly. Whether I define the keyframes ...

Dismiss the Popover in Ionic 2

After opening a popover that redirects me to another page and then returning to the root page (popToRoot), I reload the data/dom upon an event and dismiss the popup once the json data is received from the server. Everything works smoothly with a lengthy ti ...

Guide on Implementing jQuery UI Autocomplete with Chrome's Speech Input Feature

I have recently discovered a cool feature in Chrome that allows users to dictate into any input field using speech input. Learn more here. It's easy to add this feature in Chrome: <input type="text" x-webkit-speech="x-webkit-speech" /> <!-- ...

Is there a way to extract the content length from the raw DraftJS data?

I have a system where I am storing the data from my DraftJS editor in my database as a JSON string by passing it through convertToRaw(editorState.getCurrentContent()). For example, this is how the stored data looks like in the database: {"blocks": [{"key ...

Tips for transferring the output of a JavaScript async function to a Python variable

var = driver.execute_script("setTimeout(function(){ return [1,2,3]; }, 1000);") Utilizing the Selenium method execute_script, I am attempting to extract data from a website using javascript and assign it to a python variable var. The challenge a ...

The solution to enabling multiple inputs when multiple buttons are chosen

Below is a link to my jsfiddle application: http://jsfiddle.net/ybZvv/5/ Upon opening the jsfiddle, you will notice a top control panel with "Answer" buttons. Additionally, there are letter buttons, as well as "True" and "False" buttons. The functionali ...

Modify mouse pointer when an object is clicked using JavaScript

Greetings, I am in the process of designing a website for a client. I have encountered a challenge in changing the cursor icon when a user performs a mousedown on an object. There is an image on the webpage When the user clicks on the image, the cursor s ...

Ways to display or conceal dual views within a single Marionette js region

In my LayoutView, I have set up two regions: the filter region and the main region (Content Region). The main region displays a view based on the selection made in the filter region. Currently, I have a view for the main region called Current Year view. H ...

Tips on accessing files saved in a one-to-many connection using Mongoose

I have multiple Schemas set up for Shops and Products. Each shop can have a variety of products, and I currently have 5 different shops with their own unique product listings. While I am able to save the products and find their corresponding IDs within eac ...

Best practices for hiding or showing columns in a material-ui table

Currently, I am implementing the features of http://www.material-ui.com. Is there a way to dynamically hide or show columns depending on the device being used? For instance, I would like to display 6 columns on desktop but only 3 specific columns on a ph ...

What is the correct way to utilize the createAsyncThunk function in TypeScript?

You can access the entire project here. I currently have this code snippet: extraReducers: (builder) => { builder .addCase(getTodosAsync.fulfilled, (state, action:any) => { return action.payload.todos ...

Effective approach for managing a series of lengthy API requests

I am developing a user interface for uploading a list of users including their email and name into my database. After the upload process is complete, each user will also receive an email notification. The backend API responsible for this task is created u ...

What is the best way to display user input within a paragraph using React?

I've been working on a To-Do list and I have successfully implemented the functionality to add new tasks. The issue I'm facing is that when I try to add a task, it doesn't show up in the paragraph within my Todo component, even though I can ...

Floating action button within a collapsible panel

I am having trouble placing a fixed-action-btn inside a collapsible body. It keeps appearing in the bottom right corner of the page instead of within the collapsible itself. How can I ensure that the button stays inside the body? Check out this link for r ...