Empresas
Empregos
  • Sobre nós
  • Soluções
    • Publicação de vagas
      Publique sua vaga e receba candidatos qualificados em 48h.
    • Avaliações de candidatos
      Mais de 500 testes técnicos e psicológicos, mais anti-fraude.
    • Headhunting
      Busca executiva personalizada do início ao fim.
    • Folha de Pagamento + EOR
      Dispersão de folha e EOR em mais de 15 países da LATAM.
  • Preços
  • Empregos

0

280
Visualizações
How to fetch data from a custom React hook (API) with onClick and display it in a Div using TypeScript?

I'm new to TypeScript and even React Hooks. I'm trying to fetch data continuously from a custom hook called useFetch(), which takes in a string (the URL) parameter:

import { useEffect, useState } from "react";

export interface Payload {
  data: null | string,
  loading: boolean
}

const useFetch = (url: string) => {
  const [state, setState] = useState<Payload>({data: null, loading: true})

  useEffect(() => {
    setState(state => ({ data: state.data, loading: true }));
    fetch(url)
      .then(x => x.text())
      .then(y => {
        setState({ data: y, loading: false });
      });
  }, [url, setState])

  return state;
  }

export default useFetch;

I import that hook into App():

import React, { useState, useEffect } from "react";
import useFetch from './utils/useFetch'
import {Payload} from './utils/useFetch';

const App = () => {
  const [quote, setquote] = useState<Payload>({data: null, loading: true})
  const handleClick = () => setquote(data)

  const data = useFetch(
    "/api/rand"
  );

  return (
    <div>
      <h1>Quotes</h1>
      <button onClick={handleClick}>Get Quote</button>
      <div>{quote.data}</div>
    </div>
  )
}

export default App;

On the first time the app loads, it works. I get data (a quote) when I click the button.

Preview

However, when I click it multiple times, the API isn't called again, and new data doesn't come through. I believe I'm supposed to use the useEffect() react hook and maintain the state (maybe I'm mistaken) but all my attempts so far have been to no avail. Any help would be much appreciated. If I figure it out, I'll definitely answer this question. Thanks!

about 4 years ago · Juan Pablo Isaza
3 Respostas
Responde à pergunta

0

It seems like you are mixing two ideas a little bit here.

Do you want to fetch data continuously? (Continuously meaning all the time, as in, periodically, at an interval)

Or do you want to fetch data upon mount of the component (currently happens) AND when the user taps the "Get Quote" button (not working currently)?

I will try to help you with both.

Continuously / periodically

Try changing the setup a bit. Inside the useFetch do something like:

import { useEffect, useState } from "react";

export interface Payload {
  data: null | string,
  loading: boolean
}

const useFetch = (url: string) => {
  const [state, setState] = useState<Payload>({data: null, loading: true})

  useEffect(() => {
    const interval = setInterval(() => {
        setState(state => ({ data: state.data, loading: true }));
        fetch(url)
          .then(x => x.text())
          .then(y => {
            setState({ data: y, loading: false });
          });
     }, 2000); // Something like 2s

     return () => {
        clearInterval(interval); // clear the interval when component unmounts
     }
  }, [url])

  return state;
  }

export default useFetch;

This will fetch the endpoint every 2s and update the state variable, this will then be reflected in the App (or any place that uses the hook for that matter).

Therefore you do not need the quote state anymore in the App. Also, you don't need a button in the UI anymore.

App will looks something like:

import React, { useState, useEffect } from "react";
import useFetch from './utils/useFetch'
import {Payload} from './utils/useFetch';

const App = () => {
  const quote = useFetch(
    "/api/rand"
  );

  return (
    <div>
      <h1>Quotes</h1>
      <div>{quote.data}</div>
    </div>
  )
}

export default App;

Fetch data upon mount of the component (currently happens) AND when the user taps the "Get Quote" button

Then the useFetch hook isn't really needed/suited in my opinion. A hook can be used for this application, but transforming it into a more simple function would make more sense to me. I suggest omitting the useFetch hook. The App component would look something like:

import React, { useState, useEffect, useCallback } from "react";

const App = () => {
  const [quote, setQuote] = useState<Payload>({data: null, loading: true})

  const handleGetQuote = useCallback(() => {
    setQuote(state => ({ data: state.data, loading: true }));
    fetch("/api/rand")
      .then(x => x.text())
      .then(y => {
        setQuote({ data: y, loading: false });
      });
  }, []);

  useEffect(() => {
    handleGetQuote();
  }, [handleGetQuote]);

  return (
    <div>
      <h1>Quotes</h1>
      <button onClick={handleGetQuote}>Get Quote</button>
      <div>{quote.data}</div>
    </div>
  )
}

export default App;
about 4 years ago · Juan Pablo Isaza Relatório

0

Here's another possibility: I added a reload function to the return values of useFetch. Also, since the useFetch hook already contains its own state, I removed the useState from App

const useFetch = (url: string) => {
  const [state, setState] = useState<Payload>({data: null, loading: true})
  const [reloadFlag, setReloadFlag] = useState(0)

  useEffect(() => {
    if(reloadFlag !== 0){ // remove this if you want the hook to fetch data initially, not just after reload has been clicked
      setState(state => ({ data: state.data, loading: true }));
      fetch(url)
        .then(x => x.text())
        .then(y => {
          setState({ data: y, loading: false });
        });
    }
  }, [url, setState, reloadFlag])

  return [state, ()=>setReloadFlag((curFlag)=>curFlag + 1)];
  }

const App = () => {

  const [data, reload] = useFetch(
    "/api/rand"
  );

  return (
    <div>
      <h1>Quotes</h1>
      <button onClick={reload}>Get Quote</button>
      <div>{quote.data}</div>
    </div>
  )
}
about 4 years ago · Juan Pablo Isaza Relatório

0

Just change the code as below:

const useFetch = (url: string) => {
  const [state, setState] = useState<Payload>({data: null, loading: true})

  setState(state => ({ data: state.data, loading: true }));
    fetch(url)
      .then(x => x.text())
      .then(y => {
        setState({ data: y, loading: false });
      });

  return state;
  }

export default useFetch;
about 4 years ago · Juan Pablo Isaza Relatório
Responde à pergunta
Encontrar trabalhos remotos

Descubra a nova forma de encontrar um emprego!

melhores empregos
Principais categorias de trabalho
Empresas
Postar vaga Preços Comercial
Jurídico
Termos e Condições Política de privacidade
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomende algumas ofertas para mim
Preciso de ajuda