score:0

Accepted answer

the problem here is, that you are not refetching the quotes.

const usefetch = (url:string) => {
  const [loading, setloading] = usestate(false);
  const [quote, setquote] = usestate('');

  const refetch = usecallback(() => {
    setloading(true);
    fetch(url)
      .then((x) => x.text())
      .then((y) => {
        //setquote(y);
        setquote(string(math.random()));
        setloading(false);
      });
  }, [url]);

  return { quote, refetch, loading };
};

const app = () => {
  const { quote, refetch, loading } = usefetch('/api/rand');

  useeffect(() => {
    refetch();
  }, []);

  return (
    <div>
      <h1>quotes</h1>
      <button onclick={refetch}>get quote</button>
      {loading ? ' loading...' : ''}
      <div>{quote}</div>
    </div>
  );
};

see this example https://stackblitz.com/edit/react-ts-kdyptk?file=index.tsx

score: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>
  )
}

score: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;

score:2

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;

Related Query

More Query from same tag