1

I am using React Hooks to get data from an existing API. Here is my code

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

export const People = () => {
  const [people, setPeople] = useState([]);
  const url = "http://127.0.0.1:5000/people";

  async function fetchData() {
    console.log("calling api .. ");
    const res = await fetch(url);
    res.json().then((res) => setPeople(res));
  }

  useEffect(() => {
    fetchData();
  });

  return (
    <div>
      <ul>
        {people &&
          people.map((person) => <li key={person.id}>{person.name}</li>)}
      </ul>
    </div>
  );
};

const Dashboard = (props) => {
  return (
    <div>
      <People />
    </div>
  );
};

export default Dashboard;

The problem that I am having is this API is getting called over and over again. Can you please let me know what I am doing wrong here.

Thanks

Dennis Vash
  • 50,196
  • 9
  • 100
  • 118
Gagan
  • 5,416
  • 13
  • 58
  • 86

1 Answers1

3

Currently, using useEffect(callback) will execute the callback on every render.

Try using useEffect with an empty dependencies array.

If you want to run an effect and clean it up only once, you can pass an empty array ([]) as a second argument. This tells React that your effect doesn’t depend on any values from props or state, so it never needs to re-run.

  • Check my other answer on useEffect use cases.
useEffect(() => {
  fetchData();
}, []);

As for the rest of the component, it should look like so (opinioned):

// Should be on the outer scope as the URL is decoupled from the component's logic
const url = "http://127.0.0.1:5000/people";

export const People = () => {
  const [people, setPeople] = useState([]);

  useEffect(() => {
  // This way fetchData won't re-assigned on every render
    async function fetchData() {
      console.log("calling api .. ");
      const res = await fetch(URL);

      // Consitstance, don't mix `then` and `await` syntax
      const people = await res.json();
      setPeople(people);
    }

    fetchData();
  }, []);

  return (
    <div>
      <ul>
        {people &&
          people.map((person) => <li key={person.id}>{person.name}</li>)}
      </ul>
    </div>
  );
};
Dennis Vash
  • 50,196
  • 9
  • 100
  • 118
  • Thanks, it works, but what does it do ? Can you please elaborate a bit more ? thanks a ton.. – Gagan Apr 25 '20 at 19:13
  • 2
    Loop was existing because `useEffect` is called every time a state in component changes and in hook you referred to `fetchData()` which changes the state. With empty dependency array it runs only once just like `componentDidMount`. – Adrian Solarczyk Apr 25 '20 at 19:15
  • @Gagan ```useEffect``` will trigger when values of variables in second arg (as array) have change, So when there is an empty array, It means ```componentDidMount```. – Vahid Alimohamadi Apr 25 '20 at 19:17
  • Thanks, Guys.. Your help is much appreciated. – Gagan Apr 25 '20 at 19:52