Fetch and setInterval react hooks problem
Asked Answered
P

2

7

I recently used hooks with React to fetch data from server but i'm facing a problem with hooks. The code seems correct but it look like the useEffect isn't called at first time but 3 seconds after with the setInterval. I have blank table for 3 seconds before it appear. I want to directly show the data and call it 3 seconds later.

What is the correct way to use it?

const [datas, setDatas] = useState([] as any);

useEffect(() => {
  const id = setInterval(() => {
    const fetchData = async () => {
      try {
        const res = await fetch(URL);
        const json = await res.json();
        setDatas(jsonData(json));
      } catch (error) {
        console.log(error);
      }
    };
    fetchData();
  }, TIME)

  return () => clearInterval(id);
}, [])
Pteridophyte answered 30/9, 2020 at 19:29 Comment(0)
H
7

You need to invoke fetchData once initially outside the interval. Define fetchData outside the interval.

useEffect(() => {
  // (1) define within effect callback scope
  const fetchData = async () => {
    try {
      const res = await fetch(URL);
      const json = await res.json();
      setDatas(jsonData(json));
    } catch (error) {
      console.log(error);
    }
  };
    
  const id = setInterval(() => {
    fetchData(); // <-- (3) invoke in interval callback
  }, TIME);

  fetchData(); // <-- (2) invoke on mount

  return () => clearInterval(id);
}, [])
Henden answered 30/9, 2020 at 19:37 Comment(2)
You have a dangling promise here. If fetchData() take a while, they will start to pile up and call multiple fetchData() in parallel.Sphingosine
@MikaelLirbank Yes, I suppose long-running fetchData calls can pile up in this basic example. If concurrent fetches are a problem it's trivial to handle, e.g. cancel preceding in-flight requests, block new requests, etc.Henden
V
-1

With React Hooks:

  const [seconds, setSeconds] = useState(0)

  const interval = useRef(null)

  useEffect(() => { if (seconds === 60) stopCounter() }, [seconds])

  const startCounter = () => interval.current = setInterval(() => {
    setSeconds(prevState => prevState + 1)
  }, 1000)

  const stopCounter = () => clearInterval(interval.current)
Vitavitaceous answered 24/10, 2020 at 14:30 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.