简体   繁体   中英

Axios request keeps returning twice undefined and twice the data

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...

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.
  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/

Just in case, this solution helped me: https://github.com/axios/axios/issues/2825#issuecomment-883635938

"The problem in my case was caused by React development server. The strict mode in react caused the issue. I had to remove the strict mode This solved the problem of sending double requests: The strict mode checks are only run in development mode. Doc: https://reactjs.org/docs/strict-mode.html "

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 **

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM