Infinite Loop on API GET Requests - reactjs

I'm relatively new to working with APIs and I'm looking to fetch data from an API using a GET request and this code is causing an infinite loop of GET requests. What I'm ultimately looking to accomplish is to access the data I'm receiving in res.data so I can pull information from the object that's being returned in the API response (using something like res.data.name which is currently prompting an error saying res is not defined which I believe could be due to a scope issue).
const Podcast=()=>{
const[show,setShow]=useState([])
const[bestPodcasts,setBestPodcasts]=useState([])
const [genre,setGenre]=useState('')
const[data,setData]=useState({})
client.fetchBestPodcasts(
{ genre_id: '91',
page: 2,
region: 'us',
safe_mode: 0,}
)
.then((res) => {
setData(res.data)
// Get response json data here
console.log(res.data);
}).catch((error) => {
console.log(error)
})

You can make use of useEffect hook, this shall call your API only once/initially:
const Podcast = () => {
const [show, setShow] = useState([])
const [bestPodcasts, setBestPodcasts] = useState([])
const [genre, setGenre] = useState('')
const [data, setData] = useState({})
useEffect(() => {
apiCall()
}, []);
const apiCall = () => {
const data = {
genre_id: '91',
page: 2,
region: 'us',
safe_mode: 0
}
client.fetchBestPodcasts(data)
.then(res => setData(res.data))
.catch(error => console.log(error))
}
}

Related

how to map multiple nested arrays json react rails api

I have multiple nested arrays, how can I map them ? I could map only one nested with the help of #Apostolos
`
function RequestDetail({match}) {
const [request, setRequests] = useState({ user: {} });
const [fulfillment, setFulfillments] = useState({});
const [text, setText] = useState([]);
useEffect(() => {
fetchRequest();
}, []);
const fetchRequest = () => {
axios
.get(
`${baseUrl}/${match.params.id}`
)
.then((res) => {
setRequests(res.data);
console.log(res.data);
})
.catch((err) => console.log(err));
};
const handleSubmit = async (e) => {
//e.preventDefault();
const newfulfillment = {text}
try{
const response = await axios.post(`${baseUrl}/${match.params.id}/fulfillments`, newfulfillment);
setAuthHeaders();
const allFullfilments = [...fulfillment, response.data];
setFulfillments(allFullfilments);
setText('');
} catch (err) {
console.log(`Error: ${err.message}`);
}
}
`
The array I need is fulfillments
Your response is an array which contains another array fullfilments and you
u want an array with all fullfilments right?
To do so, you need to map your response, and retrieve your fullfilments, you'll have an "array of array" which you can .flat()
Something like
response.data.map(({fullfilments}) => fullfilments).flat()
Since I was using rails API, with the help of Serializers I could I get the needed data in a different way.

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();
}, []);
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]);

How to assign data to a variable from axios get() response

I am trying to use Express (axios) to build a React app.
I was able to get an array of objects from MongoDB using get() method. Currently the list is printed out to the console. How can I assign it to a variable so that I could use that array for further actions?
useEffect(() => {
const expensesListResp = async () => {
await axios.get('http://localhost:4000/app/expenseslist')
.then(
response => console.log(response.data))
}
expensesListResp();
}, []);
Many thanks!
You can assign it in the following way, let say you have an array posts:
const [posts, setPosts] = useState([]);
useEffect(() => {
axios.get('url')
.then(res => setPosts(res.data))
.catch(err => console.log(err));
}, [])
In your code, you can do it in this way:
const [resultArray, setResultArray] = useState([]);
useEffect(() => {
const expensesListResp = async () => {
await axios.get('http://localhost:4000/app/expenseslist')
.then(
response => setResultArray(response.data))
}
expensesListResp();
}, []);
I am assuming that you have data printed on the console.log(response.data) and you want it to be assigned to a variable so that you can use it right?
if that's the case you are already using async function just name it with whatever variable name you want it to be before await.
for example:
const expensesListResp = async () => {
const "your variable name" = await axios.get('http://localhost:4000/app/expenseslist')
}
you can also save that variable in your state, if you want to use that variable data throughout your application.

React Native - state is returning null after setting state

I'm very much new to react native currently i'm building small app for just getting an idea about this. I'm facing an issue in mapping the data from API. This is the json response returning from the api
{"data":[{"digit":300,"countsum":"52"},{"digit":301,"countsum":"102"},{"digit":302,"countsum":"27"},{"digit":303,"countsum":"201"},{"digit":500,"countsum":"101"}]}
When i tried to map this data i'm facing some issues. I stored the response from API to the state and when i tried to display the state data using map function it's showing the state value is null. This the code i tried till now
const [listdata, setListData] = useState(null)
useEffect(() => {
// Run! Like go get some data from an API.
getListData();
}, []);
const getListData = async () => {
const token = await AsyncStorage.getItem("#userToken")
axios
.get(constants.BASE_URL + "getlist?token=" +token)
.then(response => setListData(response.data))
.catch(error => {
console.log(error);
});
listdata.map(item => <Text>{item.digit}</Text>)
}
Do it like this,
export default function ComponentName () {
const [listdata, setListData] = useState([])
useEffect(() => {
// Run! Like go get some data from an API.
getListData();
}, []);
const getListData = async () => {
const token = await AsyncStorage.getItem("#userToken")
axios
.get(constants.BASE_URL + "getlist?token=" +token)
.then(response => setListData(response.data))
.catch(error => {
console.log(error);
});
}
return (<>
listdata.map(item => <Text>{item.digit}</Text>)
</>
);
}
You have to wait the fetch execution and later do the list map.
// wait for it
await axios
.get(constants.BASE_URL + "getlist?token=" +token)
.then(response => setListData(response.data))
.catch(error => {
console.log(error);
});
listdata.map(item => <Text>{item.digit}</Text>)
If you want to map the data then do that inside return statement of your code ,like:
return(
{listData?listdata.map(item => return <Text>{item.digit}</Text>):""}
);
This is a sample of a meant in my comment above:
Try console.log listdata at this stage, you will find that it is still
null, in other words, the value of the updated value of the
listdata:useSate will be ready after the render take place. You can
make another function outside of the current one. then use useEffect
with listdata to update your text views
const [listdata, setListData] = useState(null)
useEffect(() => makeRemoteRequest(), [listdata])
makeRemoteRequest = () => {
const url = `your-url-of-data-here`;
fetch(url)
.then(res => res.json())
.then(res => {
setListData(res.data);
})
.catch(error => {
console.log(error)
});
};
You could try the following:
const [listdata, setListData] = useState([])
useEffect(() => {
// Run! Like go get some data from an API.
getListData();
}, []);
const getListData = async () => {
const token = await AsyncStorage.getItem("#userToken")
try {
const dataResponse = await axios.get(constants.BASE_URL + "getlist?token=" +token);
setListData(dataResponse.data || [] );
} catch(error) {
console.log(error);
}
}
return (<>
listdata.map(item => <Text>{item.digit}</Text>)
</>);

Confused about using 'useState' in two separate functions

In order to get data from my AWS Postgres DB, I have to first get an AWS Access Token and pass it into the GET call. To accomplish this, in my React app, I've created a file called requests.js into which I plan to build a number of functions. Here are the first two:
// Custom hook to get AWS Auth Token
export const useGetAwsAuthToken = () => {
const [data, setData] = useState();
useEffect(() => {
const fetchData = async function() {
try {
const config = {
headers: { "Authorization":
await Auth.currentSession()
.then(data => {
return data.getAccessToken().getJwtToken();
})
.catch(error => {
})
}
};
setData(config);
} catch (error) {
throw error;
} finally {
}
};
fetchData();
}, []);
return { data };
};
// Custom hook for performing GET requests
export const useFetch = (url, initialValue) => {
const [data, setData] = useState(initialValue);
const [loading, setLoading] = useState(true);
useEffect(() => {
const fetchData = async function() {
try {
setLoading(true);
const response = await axios.get(url);
if (response.status === 200) {
setData(response.data);
}
} catch (error) {
throw error;
} finally {
setLoading(false);
}
};
fetchData();
}, [url]);
return { loading, data };
};
I was under the impression that I could use const [data, setData] = useState(); in both of these functions and that they would be independent of each other. However, back where I call the functions, my IDE is telling me that "data has already been declared" with the 2nd call:
const {data} = useGetAwsAuthToken();
const {loading, data} = useFetch('https://jsonplaceholder.typicode.com/posts');
Furthermore, say I comment out the 2nd line of code above and make this call:
const {data2} = useGetAwsAuthToken();
This leaves data2 as undefined. This is also confusing because shouldn't I be able to have any named return value variable in the calling function?
First, the one that is easier to answer for me: const {data2} = useGetAwsAuthToken isn't valid because you're using destructuring and it's expecting the value of data. So what you're telling it is the equivalent of saying const data2 = useGetAwsAuthToken().data2 What you actually want is const { data: data2 } = useGetAwsAuthToken(). This will take the value that is returned (data) and save it to the current scope as data2.
Now for the first issue you brought up. Why are you using react life cycles in what appears to just be a function? You don't need to save things in state when it's just a function that's not returning a React Component.

Resources