Search code examples
reactjsapiaxiosreact-hooksstrapi

My UseEffect either calls an infinite time my API and my data is showing or calls it once but the data is not showing


I am retrieving data with an Axios "get" request but the problem is that, if I put my function fetchResult() in the dependencies of my UseEffect() it shows my data in my console.log and in my DataGrid component BUT calls my API infinite, or if I put my dependencies array as empty it DOES call my API one time (what I want) but for a reason that I don't know my console.log is empty and my DataGrid too, I have a chance on 1000 to see my data when I let it like this.

const [clients, setClients] = useState([]);
const [rows, setRows] = useState([]);
const [loading, setLoading] = useState(false);

function fetchClients() {
  if (loading === false) {
    axios
      .get(API_URL_CLIENTS + "?users_permissions_user.email=" + USER_KEY_EMAIL)
      .then((response) => {
        if (response.status === 200) {
          setClients(response.data);
          let test;
          console.log(clients);
          test = clients.map((client) => {
            return {
              id: client.id,
              col1: client.nom,
              col2: client.prenom,
              col3: client.mail,
              col4: client.telephone,
            };
          });
          setRows(test);
        }
      })
      .catch((error) => {
        console.log(error);
      })
      .finally(() => {
        setLoading(true);
      });
  }
  setLoading(false);
}

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

Solution

  • I think that at least part of your issue is caused by you setting and checking loading true/false within the called function.

    Why are you setting "setLoading" to true when the axios call is completed instead of before? I assume the reason is that you are displaying a spinner while your axios call is performed?

    I'd probably do something like below instead. Note that I have made some assumptions:

    loading should be set to true before performing the axios call

    loading is set to false when it is completed (regardless of success/error)

    you do not want to make the request again if clients array has been populated

    const [clients, setClients] = useState([]);
    const [rows, setRows] = useState([]);
    const [loading, setLoading] = useState(false);
    
    function fetchClients() {
        setLoading(true);
        axios
            .get(API_URL_CLIENTS + "?users_permissions_user.email=" + USER_KEY_EMAIL)
            .then((response) => {
                if (response.status === 200) {
                    setClients(response.data);
                    let test;
                    console.log(clients);
                    test = clients.map((client) => {
                        return {
                            id: client.id,
                            col1: client.nom,
                            col2: client.prenom,
                            col3: client.mail,
                            col4: client.telephone,
                        };
                    });
                    setRows(test);
                }
            })
            .catch((error) => {
                console.log(error);
            })
            .finally(() => {
                setLoading(false);
            });
    }
    
    useEffect(() => {
        if (!loading && clients.length === 0) {
            fetchClients();
        };
    }, [loading, clients]);