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('');
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...
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...
Share Improve this question edited Jan 16, 2022 at 19:50 Liss asked Jan 16, 2022 at 19:07 LissLiss 231 silver badge5 bronze badges 12- Hi Liss, wele to Stack Overflow! Can you please provide a MRE? – Urmzd Commented Jan 16, 2022 at 19:11
-
1
Use the
loading
export to circumvent that (And set it to false after the get request is sucessfull). – madflow Commented Jan 16, 2022 at 19:11 - 1 Don't use await with .then. Also hooks won't wait for async function to return set state before returning. – serkanz Commented Jan 16, 2022 at 19:13
-
@madflow I'm more interested in the repeated calls. I think the
loading
or undefined issue is secondary. Still a good way of preventing undefined, but I don't think that's the underlying issue – Urmzd Commented Jan 16, 2022 at 19:14 -
The
data
state variable will be undefined on first load. You could try setting it to an empty array as initial value like soconst [data, setData] = useState([]);
and it might stop it from breaking your app, but without more details, it's hard to troubleshoot. – codemonkey Commented Jan 16, 2022 at 19:15
4 Answers
Reset to default 3Just in case, this solution helped me : https://github./axios/axios/issues/2825#issuement-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/docs/strict-mode.html "
When the effect runs you:
setLoading(true)
- Send the Ajax request
setLoading(false)
Later, then the Ajax response arrives you:
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:
- Move
setLoading(false)
inside thethen
callback so it doesn't get set until after you havesetData(response.data)
- Get rid of
loading
entirely and base your logic offdata
beingundefined
or having a different value.
- 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.
- 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 following url and where to setloading and other needed states. https://www.robinwieruch.de/react-hooks-fetch-data/
One of the effects of using <React.StrictMode> is that it can cause certain methods, like ponentDidUpdate(), getDerivedStateFromProps(), and UNSAFE_ponentWillMount(), to be called twice. This is done intentionally to help developers find potential issues in their code.
In your case, the double fetch was caused by the fact that the useEffect hook was being called twice because of the <React.StrictMode> ponent. Removing the <React.StrictMode> ponent resolved the issue, as it prevented the double calling of hooks.
In general, it is remended to avoid using <React.StrictMode> in production environments and only use it during development to catch potential issues early.