title: React DOM update on fetch
body: <p>I'm working on a typescript react project to add and display some accounts on a wallet..
  I have created a useAPI function that makes my calls and returns the state of the call as well as the retrieved data</p>
  <p><strong>api/index.ts</strong></p>
  <pre><code>import { useCallback, useEffect, useState } from &quot;react&quot;;
  
  export type ApiMethod = &quot;GET&quot; | &quot;POST&quot;;
  
  export type ApiState = &quot;idle&quot; | &quot;loading&quot; | &quot;done&quot; | &quot;failed&quot;;
  
  const fetcher = async (
      url: string,
      method: ApiMethod,
      payload?: string,
    ): Promise&lt;any&gt; =&gt; {
      const requestHeaders = new Headers();
      requestHeaders.set(&quot;Content-Type&quot;, &quot;application/json&quot;);
      const res = await fetch(url, {
        body: payload ? JSON.stringify(payload) : undefined,
        headers: requestHeaders,
        method,
      });
      //const resobj = await res.json();
      return res;
    };
  
  export function useApi(
    url: string,
    method: ApiMethod,
    payload?: any
  ): {
    apiState: ApiState;
    data: [];
    execute: () =&gt; void;
  } {
    const [apiState, setApiState] = useState&lt;ApiState&gt;(&quot;idle&quot;);
  
    const [data, setData] = useState&lt;[]&gt;([]);
    const [toCallApi, setApiExecution] = useState(false);
  
    const execute = () =&gt; {
      console.log(&quot;executing api call&quot;);
      setApiExecution(true);
    };
  
  
    const fetchApi = useCallback(async () =&gt; {
      fetcher(url, method, payload)
      .then((res) =&gt; {
          if(!res.ok){
              return &quot;error&quot;
          }
          return res.json()
      })
      .then((result) =&gt; {
          if(result === &quot;error&quot;) setApiState(&quot;failed&quot;)
          else{
              setData(result)
              setApiState(&quot;done&quot;)
          }
      })
    }, [method, payload, url]);
  
    // call api
    useEffect(() =&gt; {
      if (toCallApi &amp;&amp;  apiState === &quot;idle&quot;) {
        console.log(&quot;calling api&quot;);
        setApiState(&quot;loading&quot;);
        fetchApi();
      }
    }, [apiState, fetchApi, toCallApi]);
  
    console.log(url,data, apiState, payload)   
  
    return {
      apiState,
      data,
      execute,
    };
  }
  </code></pre>
  <p>After this I call this function on my <code>app.tsx</code> first inside a <code>useEffect</code> hook to retrieve the accounts when my DOM loads.</p>
  <p>And then I have the possibility to create a new Account, and display with the previous accounts.</p>
  <p><strong>PROBLEM:</strong></p>
  <p>The problem here is, when I create a new Account or when I get a <code>failed</code> state, I cannot display the account or the error message until I reload my page.</p>
  <p>Though I need to update my DOM once I create an account or get an error to actually display it.</p>
  <p><strong>app.tsx</strong></p>
  <pre><code>function App() {
   
    const [selectedCurrency, setSelectedCurrency] = useState(&quot;&quot;)
    const [errorIsOpen, setErrorIsOpen] = useState(false)
  
    const accounts = useApi(
      `${process.env.REACT_APP_PROXY}/accounts`,
      &quot;GET&quot;,
    )
  
    const wallets = useApi(
      `${process.env.REACT_APP_PROXY}/wallets`,
      &quot;GET&quot;,
    )
  
    const createWallet = useApi(
      `${process.env.REACT_APP_PROXY}/accounts`,
      &quot;POST&quot;,
      {currency: selectedCurrency}
    )
  
    const [isOpen, setIsOpen] = useState(false)
  
    useEffect(() =&gt; {
      accounts.execute()
    }, [accounts])
  
    useEffect(() =&gt; {
      if(isOpen){
        wallets.execute()
      }
    }, [isOpen, wallets])
  
    const handleWalletCreate = async () =&gt; {
      createWallet.execute()
      accounts.execute()
      if(createWallet.apiState === &quot;failed&quot;){
        setErrorIsOpen(true)
      }
    }
   
    
  
    return (
      &lt;&gt;
        &lt;Modal isOpen={isOpen}&gt;
          {
            wallets.apiState === &quot;loading&quot; &amp;&amp; 
            &lt;div className='center'&gt;
              &lt;Loader size={100} width={8}/&gt;
            &lt;/div&gt;
          }
          { 
            (wallets.apiState === &quot;done&quot; &amp;&amp; wallets.data)  &amp;&amp;
            &lt;div className=&quot;modal-content&quot;&gt;
              &lt;div className='modal-content-header'&gt;
                &lt;h3&gt;Add new wallet&lt;/h3&gt;
                &lt;span onClick={() =&gt; setIsOpen(!isOpen)}&gt;
                  &lt;Close /&gt;
                &lt;/span&gt;
              &lt;/div&gt;
  
              &lt;div className='info'&gt;
                &lt;p&gt;
                The crypto wallet will be created instantly and be available in your list of wallets.
                &lt;/p&gt;
              &lt;/div&gt;
  
              &lt;div className='form'&gt;
                &lt;h4&gt;Select wallet&lt;/h4&gt;
                &lt;select defaultValue=&quot;DEFAULT&quot; onChange={(e) =&gt; setSelectedCurrency(e.target.value)}&gt;
                  &lt;option value=&quot;DEFAULT&quot; disabled&gt;Select currency&lt;/option&gt;
                  {wallets.data.map((wallet: any, i) =&gt; 
                  &lt;option key={i} value={wallet.currency}&gt;{wallet.name}&lt;/option&gt;
                    )}
                &lt;/select&gt;
                &lt;div className='btn-container'&gt;
                    &lt;button className='btn-submit' onClick={handleWalletCreate}&gt;
                      Create wallet
                    &lt;/button&gt;
                &lt;/div&gt;
              &lt;/div&gt;
  
              {
                
                (createWallet.apiState === &quot;failed&quot; || errorIsOpen) &amp;&amp;
                &lt;div className=&quot;create-wallet-error&quot;&gt;
                  &lt;div&gt;
                    &lt;NetworkError /&gt;
                    &lt;span&gt;Network Error&lt;/span&gt;
                  &lt;/div&gt;
                  &lt;CloseError onClick={() =&gt; setErrorIsOpen(!errorIsOpen)}/&gt;
                &lt;/div&gt;
                
              }
            &lt;/div&gt;
          }
  
          {
            wallets.apiState === &quot;failed&quot; &amp;&amp;
            &lt;div className='center'&gt;
              &lt;div className='network-error'&gt;
                &lt;div className='error-logo'&gt;
                  &lt;ErrorIcon /&gt;
                &lt;/div&gt;
                &lt;h3&gt;Network Error&lt;/h3&gt;
                &lt;div className=&quot;btn-container&quot;&gt;
                  &lt;button className=&quot;btn-submit&quot; onClick={wallets.execute}&gt;
                    Try again
                  &lt;/button&gt;
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;
          }
        &lt;/Modal&gt;
  
        &lt;div className=&quot;main&quot;&gt;
          &lt;header&gt;
            &lt;div className=&quot;header-container&quot;&gt; 
              &lt;div className='logo'&gt;
                  &lt;Logo /&gt;
              &lt;/div&gt;
              &lt;div className='profile'&gt;
                &lt;span className='profile-picture'&gt;
                  O
                &lt;/span&gt;
                &lt;h3 className=&quot;profile-name&quot;&gt;
                  Oluwatobi Akindunjoye
                &lt;/h3&gt;
              &lt;/div&gt;
            &lt;/div&gt;
          &lt;/header&gt;
  
          &lt;section className='dashboard'&gt;
            &lt;div className='dashboard-container'&gt;
              &lt;div className='left-section'&gt;
                &lt;ul&gt;
                  &lt;li&gt;Wallets&lt;/li&gt;
                  &lt;li&gt;Prices&lt;/li&gt;
                  &lt;li&gt;Peer2Peer&lt;/li&gt;
                  &lt;li&gt;Activity&lt;/li&gt;
                  &lt;li&gt;Settings&lt;/li&gt;
                &lt;/ul&gt;
              &lt;/div&gt;
              &lt;div className='right-section'&gt;
                &lt;div className='right-section-header'&gt;
                  &lt;h1&gt;Wallets&lt;/h1&gt;
                  &lt;span onClick={() =&gt; setIsOpen(!isOpen)} className={accounts.apiState === &quot;failed&quot; ? &quot;hide&quot; : &quot;&quot;}&gt;
                    + Add new wallet
                  &lt;/span&gt;
                &lt;/div&gt;
                &lt;div className={accounts.apiState === &quot;failed&quot; ? &quot;hide&quot; : &quot;separator&quot;}&gt;&lt;/div&gt;
                &lt;div className='right-section-content'&gt;
                  { 
                    accounts.apiState === &quot;loading&quot; &amp;&amp; 
                    &lt;div className='center'&gt;
                      &lt;Loader size={100} width={8}/&gt;
                    &lt;/div&gt;
                  }
  
                  {
                    accounts.apiState === &quot;failed&quot; &amp;&amp;
                    &lt;div className='center'&gt;
                      &lt;div className='network-error'&gt;
                        &lt;div className='error-logo'&gt;
                          &lt;ErrorIcon /&gt;
                        &lt;/div&gt;
                        &lt;h3&gt;Network Error&lt;/h3&gt;
                        &lt;div className=&quot;btn-container&quot;&gt;
                          &lt;button className=&quot;btn-submit&quot; onClick={accounts.execute}&gt;
                            Try again
                          &lt;/button&gt;
                        &lt;/div&gt;
                    &lt;/div&gt;
                    &lt;/div&gt;
                    
                  }
                  {
                    (accounts.apiState === &quot;done&quot; &amp;&amp; accounts.data) &amp;&amp;
                    &lt;div className='accounts-cards'&gt;
                        { accounts.data.length &amp;&amp;
                          accounts.data.map((account: any, i) =&gt; 
                            &lt;div className='card' key={i}&gt;
                              &lt;div className='card-header'&gt;
                                &lt;img src={account.imgURL} alt={account.name} /&gt;
                                &lt;h4&gt;{account.name}&lt;/h4&gt;
                              &lt;/div&gt;
                              &lt;div className='card-balance'&gt;
                                {account.balance.replace(/\B(?=(\d{3})+(?!\d))/g, &quot;,&quot;)} {account.currency}
                              &lt;/div&gt;
                              &lt;div className='card-btn'&gt;
                                &lt;Arrow /&gt;
                              &lt;/div&gt;
                            &lt;/div&gt;
                          )
                        }
                    &lt;/div&gt;
                  }
                &lt;/div&gt;
              &lt;/div&gt;
            &lt;/div&gt;
          &lt;/section&gt;
        &lt;/div&gt;
      &lt;/&gt;
    );
  }
  </code></pre>
  <p>Thanks for your help.</p>