Search code examples
javascriptreactjsfetch-apiconditional-rendering

Re-render a rendered component with async Fetch called by Callback button Reactjs


I'm new in react and I'm creating an application that has the purpose of performing calculations to make cryptocurrencies strategies, the thing is that, I already have the programmed API but I need the data to be updated through a callback that re-renders data obtained from an Asynchronous API fetch just like the Binance page https://www.binance.com/es-LA/convert where it shows you a price and when you press the update button it renders with the updated data

I still don't get along with hooks and I even thought to using Jquery to use that function, in which case it would be with ajax but I want to do everything in react so as not to include more libraries

my json is like that

{
      "response": "1",
      "remesaspatria": {
        "LTCUSD": "60.990000000000002",
        "LTCEUR": "60.178832999999997"
      },
      "Binance_LTCUSD": {
        "mins": 5,
        "price": "61.03271805"
      },
      "patriaexchange": {
        "BSPTR": "421,99",
        "PTRBTC": "415,46134749",
        "PTRLTC": "1,13874534",
        "USDPTR": "53,73",
        "USDBTC": "22.324,64",
        "USDLTC": "61,19",
        "BSUSD": "7,98"
      },
      "monitorweb": {
        "BCV": "7,984",
        "ENPARALELOV": "8,10",
        "DOLARTODAY": "8,16",
        "MONITORWEB": "8,17"
      }
    }

my app.js file

import React, { useState, useEffect } from 'react'
import { useFetch } from './fetchData'

const PillContents = (n) => {
  const data ='https://api.mysite.site/?site=crypto&apikey=mykey' // API URL
  const { loading, apiData } = useFetch(data)
  //const [apiV, apiVUP] = useState('')

  const [valuesC, setValuesC] = useState({ refB: 'hidden' })

  const handleCalc = () => {
    setValuesC({ ...valuesC, refB: '' })
  }
  const handleRef = () => {
    ... here is going to be a update vars function  ...
  }
  return (
    <MDBRow>
      <MDBCol md='6' className='mb-4'>
        <form>
          <MDBRow className='mb-4'>
              <MDBBtn className='mb-4' type='button' id='calc' onClick={handleCalc}>
                CALCULAR
              </MDBBtn>
              <MDBTooltip tag='span' wrapperClass='d-inline-block' placement='top' title='Actualizar precios'>
                <MDBBtn className={`mb-4 ${valuesC.refB}`} type='button' style={{ marginLeft: 5 }} id='refc'
                  onClick={handleRef}>
                  ACTUALIZAR
              </MDBBtn>
            </MDBTooltip>
          </MDBRow>
        </form>
      </MDBCol>
    </MDBRow>
  )
}

fetchdata.js file

import { useState, useEffect } from 'react'

export const useFetch = (url) => {
  const [apiData, setApiData] = useState([])
  const [loading, setLoading] = useState(true)

  useEffect(() => {
    // Async request
    const getData = async () => {
      const response = await fetch(url)
      const apiData = await response.json()
      setApiData(apiData)
      setLoading(false)
    }
    getData()
  }, [url])
  return { loading, apiData }
}

Solution

  • You could use a mutate function and return it in your custom hook (just like SWR library).

    app.js

    import React, { useState, useEffect } from 'react'
    import { useFetch } from './fetchData'
    
    const PillContents = (n) => {
      const data ='https://api.mysite.site/?site=crypto&apikey=mykey' // API URL
      const { loading, apiData, mutate } = useFetch(data)
      //const [apiV, apiVUP] = useState('')
    
      const [valuesC, setValuesC] = useState({ refB: 'hidden' })
    
      const handleCalc = () => {
        setValuesC({ ...valuesC, refB: '' })
      }
      const handleRef = () => {
        mutate();
      }
      return (
        <MDBRow>
          <MDBCol md='6' className='mb-4'>
            <form>
              <MDBRow className='mb-4'>
                  <MDBBtn className='mb-4' type='button' id='calc' onClick={handleCalc}>
                    CALCULAR
                  </MDBBtn>
                  <MDBTooltip tag='span' wrapperClass='d-inline-block' placement='top' title='Actualizar precios'>
                    <MDBBtn className={`mb-4 ${valuesC.refB}`} type='button' style={{ marginLeft: 5 }} id='refc'
                      onClick={handleRef}>
                      ACTUALIZAR
                  </MDBBtn>
                </MDBTooltip>
              </MDBRow>
            </form>
          </MDBCol>
        </MDBRow>
      )
    }
    

    fetchdata.js

    import { useState, useEffect } from 'react'
    
    export const useFetch = (url) => {
      const [apiData, setApiData] = useState([])
      const [loading, setLoading] = useState(false)
    
      const mutate = async () => {
        setLoading(true)
        const response = await fetch(url)
        const apiData = await response.json()
        setApiData(apiData)
        setLoading(false)
      }
    
      useEffect(() => {
        mutate();
      }, [url])
    
      return { loading, apiData, mutate }
    }
    

    I just renamed your getData function and moved it to useFetch scope.

    note: you can also take advantage of useCallback hook to prevent useless re-renders.