Home > Net >  Axios request keeps returning twice undefined and twice the data
Axios request keeps returning twice undefined and twice the data

Time:01-17

I'm trying to fetch an api on a custom reactjs hook using Axios. I keep getting twice the response as undefined and after that twice as a successful fetch with the data. The undefined breaks my app.

Btw I'm fetching from the randomuser api.

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

export const useFetch = (url) => {
    const [loading, setLoading] = useState(false);
    const [data, setData] = useState([]);
    const [error, setError] = useState('')

    const getData = () => {
        setLoading(true)
        try {
            axios.get(url)
                .then(response => setData(response.data));
                setLoading(false)
          } catch (error) {
            setError(error)
          }
    };

    useEffect(() => {
        getData()
    }, [url])

    return {loading, data, error}
}

Trying to use it here and map over it

import React, { useEffect, useState } from 'react';
import { useParams } from 'react-router-dom';
import { useFetch } from '../custom_hooks/useFetch';

const PersonDetails = () => {

    const { loading, data , error } = useFetch('https://randomuser.me/api?results=20');
    const { results } = data;
    const { id } = useParams();

    const [person, setPerson] = useState({})

    useEffect(() => {
        const newPerson = results?.find(person => person.login.uuid === parseInt(id))
        setPerson(newPerson)
        console.log(newPerson)
    }, [])

    return (
        <div>
            {person.name.first}
        </div>
    )
}

export default PersonDetails

This is the thing I actually Im trying to do, but now because it is undefined, I get that cannot read properties of undefined...

CodePudding user response:

When the effect runs you:

  1. setLoading(true)
  2. Send the Ajax request
  3. setLoading(false)

Later, then the Ajax response arrives you:

  1. setData(response.data)

Since you depend on loading to determine if data is set or not, it breaks.

There are two things you could do:

  1. Move setLoading(false) inside the then callback so it doesn't get set until after you have setData(response.data)
  2. Get rid of loading entirely and base your logic off data being undefined or having a different value.

CodePudding user response:

  1. you should define the getData function inside the useeffect or pass it in dependency array and wrap the function by usecallback to avoid unnecessary rerenders.
  2. you should use abortcontroller in case of cancelations and to have cleanup function in useeffect. (in this case it's better to define getdata body in useeffect)
    useEffect(() => {
        const controller = new AbortController();
        const getData = async () => {
           setLoading(true)
           try {
                await axios.get(url, {signal: controller.signal})
                .then(response => setData(response.data));
               } catch (error) {
                setError(error)
               }
            }
        getData()
        return()=>controller.abort()
     },[url]}

you can read more about fetching data with hooks in this url: https://www.robinwieruch.de/react-hooks-fetch-data/

CodePudding user response:

fetching data takes time, console.log doesn't wait for the response, and it prints undefined, ** keep that in mind fetch is an asynchronous task **

  •  Tags:  
  • Related