title: React: I believe I have a GOTCHA for a double async fetch call. I click the button once part of the setState renders I click again and then it renders
body: <p>Question:</p>
  <p>I am developing a small app that is a memory game of Formula One Drivers to practice React. It makes a call to an API to get the driver info then I have to make a second API call to Wikipedia to get the driver images. When I submit the year and click the button it will only load half the information <strong>Image 1</strong> &amp; <strong>getDrivers function</strong>. When I click the button again it will load the images <strong>Image 2</strong> &amp; <strong>getDriversImgs function / retrievingImgUrl</strong>.</p>
  <p>I believe I am encountering a GOTCHA or doing something fundamentally wrong. I am not sure in my setDrivers call in the retrievingImgUrl() function if it isn't updating because it is a reference to an array even though I use map and it should be returning a new array?</p>
  <p>Or is this something where I need to use useEffect or useCallback to have the code rerender in one go?</p>
  <p>Any advice on how to fix the bug and if you could point me in a direction to possibly clean up these fetch calls or would you consider this clean code (like conceptually chaining fetch calls together in smaller functions or should I make it one big function)?</p>
  <pre><code>import { Fragment, useState, useEffect } from &quot;react&quot;;
  
  // Components
  import Header from &quot;./components/header/Header&quot;;
  import CardList from &quot;./components/main/CardList&quot;;
  import Modal from &quot;./components/UI/Modal&quot;;
  
  // CSS
  import classes from &quot;./App.module.css&quot;;
  
  function App() {
    const [drivers, setDrivers] = useState([]);
  
    const getDrivers = async (year) =&gt; {
      const response = await fetch(
        &quot;https://ergast.com/api/f1/&quot; + year + &quot;/drivers.json&quot;
      );
      const data = await response.json();
  
      let driverInfo = [];
      data.MRData.DriverTable.Drivers.map((driver) =&gt; {
        driverInfo.push({
          id: driver.code,
          firstName: driver.givenName,
          lastName: driver.familyName,
          wikipedia: driver.url,
          image: null,
        });
      });
      setDrivers(driverInfo);
      getDriversImgs();
    };
  
    async function getDriversImgs() {
      console.log(drivers);
      const responses = await Promise.all(
        drivers.map((driver) =&gt; {
          let wikiPageName = driver.wikipedia.split(&quot;/&quot;).slice(-1).toString();
          let wiki_url =
            &quot;https://en.wikipedia.org/w/api.php?origin=*&amp;action=query&amp;titles=&quot; +
            wikiPageName +
            &quot;&amp;prop=pageimages&amp;format=json&amp;pithumbsize=500&quot;;
          return fetch(wiki_url);
        })
      );
      const urls = await Promise.all(responses.map((r) =&gt; r.json())).then(
        (json) =&gt; retrievingImgUrl(json)
      );
      setDrivers((prev) =&gt; {
        return prev.map((item, idx) =&gt; {
          return { ...item, image: urls[idx] };
        });
      });
    }
  
    const retrievingImgUrl = async (data) =&gt; {
      console.log(data);
      const strippingData = data.map((d) =&gt; {
        return d.query.pages;
      });
      const urls = strippingData.map((d) =&gt; {
        const k = Object.keys(d)[0];
        try {
          return d[k].thumbnail.source;
        } catch {
          return null;
        }
      });
      return urls;
    };
  
  
    return (
      &lt;Fragment&gt;
        &lt;Header getDrivers={getDrivers} /&gt;
        &lt;CardList drivers={drivers} /&gt;
      &lt;/Fragment&gt;
    );
  }
  
  export default App; 
  </code></pre>
  <p>Image 1 (clicked button once):
  <a href="https://i.stack.imgur.com/aeYPN.jpg" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/aeYPN.jpg" alt="enter image description here" /></a></p>
  <p>Image 2 (clicked button twice):
  <a href="https://i.stack.imgur.com/X78XQ.jpg" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/X78XQ.jpg" alt="enter image description here" /></a></p>
  <p>Object20Object error:</p>
  <pre><code>const Header = (props) =&gt; {
    const driverYear = useRef();
  
    const driverYearHandler = (e) =&gt; {
      e.preventDefault();
      console.log(driverYear);
      const year = driverYear.current.value;
      console.log(typeof year);
      props.getDrivers(year.toString());
    };
  
    return (
      &lt;header className={classes.header}&gt;
        &lt;Title /&gt;
        &lt;form onSubmit={driverYearHandler}&gt;
          {/* &lt;label htmlFor=&quot;year&quot;&gt;Enter Year:&lt;/label&gt; */}
          &lt;input
            type=&quot;text&quot;
            id=&quot;year&quot;
            ref={driverYear}
            placeholder=&quot;Enter Year:&quot;
          /&gt;
          &lt;button onClick={props.getDrivers}&gt;Get Drivers&lt;/button&gt;
        &lt;/form&gt;
      &lt;/header&gt;
    );
  };
  
  export default Header;
  
  </code></pre>
  <p>Console Error:
  <a href="https://i.stack.imgur.com/5foZm.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/5foZm.png" alt="enter image description here" /></a>
  <a href="https://i.stack.imgur.com/iMEJp.png" rel="nofollow noreferrer"><img src="https://i.stack.imgur.com/iMEJp.png" alt="enter image description here" /></a></p>
  <p><strong>UPDATED FETCH CALL</strong></p>
  <pre><code>const getDrivers = async (year) =&gt; {
      console.log(&quot;Running more than once??&quot;);
      const url = &quot;https://ergast.com/api/f1/&quot; + year + &quot;/drivers.json&quot;;
      const response = await fetch(url);
      const data = await response.json();
  
      let driverInfo = [];
      data.MRData.DriverTable.Drivers.map((driver) =&gt; {
        driverInfo.push({
          id: driver.code,
          firstName: driver.givenName,
          lastName: driver.familyName,
          wikipedia: driver.url,
          image: null,
        });
      });
      getDriversImgs(driverInfo).then((data) =&gt; setDrivers(data));
      console.log(&quot;Here is driver info&quot;, driverInfo);
    };
  
    const getDriversImgs = async (driverInfo) =&gt; {
      const responses = await Promise.all(
        driverInfo.map((driver) =&gt; {
          let wikiPageName = driver.wikipedia.split(&quot;/&quot;).slice(-1).toString();
          let wiki_url =
            &quot;https://en.wikipedia.org/w/api.php?origin=*&amp;action=query&amp;titles=&quot; +
            wikiPageName +
            &quot;&amp;prop=pageimages&amp;format=json&amp;pithumbsize=500&quot;;
          return fetch(wiki_url);
        })
      );
      const urls = await Promise.all(responses.map((r) =&gt; r.json())).then(
        (json) =&gt; retrievingImgUrl(json)
      );
      return driverInfo.map((item, idx) =&gt; {
        return { ...item, image: urls[idx] };
      });
    };
  
    const retrievingImgUrl = async (data) =&gt; {
      const strippingData = data.map((d) =&gt; {
        return d.query.pages;
      });
      const urls = strippingData.map((d) =&gt; {
        const k = Object.keys(d)[0];
        try {
          return d[k].thumbnail.source;
        } catch {
          return null;
        }
      });
      return urls;
    };
  
  </code></pre>