Problems with fetch calls with Axios in React - reactjs

I am trying to use the https://api.randomuser.me/ API to get the data from a person. As for now, I am trying to get only his first and second names, and date of birth, but I don't know if I am doing the call to the API wrong or what I am doing incorrectly. This is the code I have:
import Axios from 'axios'
import { useState } from 'react';
function FetchCall() {
const[name,setName] = useState("")
const[birth,setBirth] = useState("")
const getInfo = () => {
Axios.get("https://api.randomuser.me/").then(
(response) => {
setName(response.results.name.first + " " + response.results.name.last);
setBirth(response.dob.date);
}
);
};
return(
<div>
Hello
<button onClick={getInfo}>Get User</button>
{name}
{birth}
</div>
);
}
export default FetchCall;
I am getting a "Unhandled Rejection (TypeError): Cannot read property 'name' of undefined" error when clicking on the button.

Axios response stores response json in .data field
response.results should be changed into response.data.results
Also, just a note, results is an array, so you need to apply indexer as well. For example, response.data.results[0].name.first
Check out React dev tools to set breakpoints and find which item in sequence is undefined

Related

Display firebase data with react

I'm new to react, so please give me some slack. I'm trying to extract data from a collection in firebase based on the url and display it on the page. My attempt is below:
import React, { useEffect, useState, map } from "react";
import { useParams } from "react-router-dom";
import { db } from "../../firebase";
import { doc, getDoc } from "firebase/firestore";
export default function UserPage() {
const { userUrl } = useParams();
const [user, setUser] = useState();
const docUserInfo = doc(db, "userinfo", userUrl);
useEffect(() => {
getDoc(docUserInfo).then((doc) => {
setUser(doc.data());
});
});
return (
<>
<div>
{user.map((user) => (
<div>{user.title}</div>
))}
</div>
</>
);
}
I get an error saying:
TypeError: Cannot read properties of undefined (reading 'map')
According to other posts here, this error suggests that my object (user) is not an array, and it doesn't seem to be. I tried using typeof to understand what type of object it is, but it just says "object". So I checked using Array.isArray(), which returns false, but here is where I get stuck.
Using setUser(doc.data().title) gives me what I want, sort of, but I want all the items inside the user array and don't want to create a useState for all of them. I also don't think there is an issue with useParams().
In addition, sometimes undefined is returned and sometimes this is done in an infinite loop, but I haven't figured out exactly when this happens.
Lastly, there are a lot of tutorials for exactly what I'm trying to do, but all of them are just displaying the fetched data in in the console (which I'm able to do), or they are using firebase<v9.
Your code loads a single document from Firestore, so there's no need to loop over multiple users as you'd do with the user.map that you have. Instead, just display the properties from your user state variable:
return (
<>
<div>
<div>{user.title}</div>
</div>
</>
);

Cannot read property 'questions' of undefined

In this application, I am trying to create a quiz application.
import React, { useState, useEffect, Component } from 'react';
const axios = require('axios').default;
const PlayQuiz = () => {
// declaring all the state here
const [questionsArray, setQuestionsArray] = useState([]);
// Using effects here
useEffect(() => {
axios({
method: 'get',
url: 'https://opentdb.com/api.php?amount=10',
}).then(res => {console.log(Object.values(res.data)[1]); setQuestionsArray(Object.values(res.data)[1])})
.catch(err => console.error(err))
}, []);
useEffect(() => {console.log(questionsArray)}, [questionsArray]);
// Returning html markup here
return (<>
<div className = 'questions-container'>
{/* {questionsArray.map(questionObject => <h1>{questionObject.question}</h1>)} */}
<h1>{questionsArray[0].question}</h1>
</div>
</>)
}
export default PlayQuiz;
(btw all the console logs that this code contains is just for me to visualise of what exactly is going on)
In the following code, I use axiosto fetch data from the API and then resolve the data in my questionsArray. Then I want to print a heading tag into my dom which contains the first element inside my array, i.e. the object and get that object's question property which contains the actual question. But when I do this: <h1>{questionsArray[0].questions}</h1>, it throws an error, saying cannot read property questions of undefined.
Just in case, if anyone of you want to see the object that I get from the API:
And from this object, I get the results object value from the data key in the object, and set it to questionsArray.
If anyone of you wants to see what gets stored inside my questionsArray:
How can I fix this error?
You can try optional chaining ?.
<h1>{questionsArray[0]?.question}</h1>
Check this out:
https://codesandbox.io/s/strange-lovelace-06u3x?file=/src/App.js
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Operators/Optional_chaining
When React is rendering your data, axios is not completely fetced your data and your questionsArray is either undefined or empty. Just check if axios is finished fetching data.
return (<>
<div className = 'questions-container'>
{/* {questionsArray && questionsArray.map(questionObject => <h1>{questionObject.question}</h1>)} */}
<h1>{questionsArray[0].question}</h1>
</div>
</>)
This will ensure your data is defined or not empty

Deeply Nested API printing

I am working on a simple app that will print out images from an API. The API is pretty nested and I already made it into TS to view schema and looked at in Postman (nothing is wrong with the API this is an error on my part.) I know where the error is but I think I need some guidance here.
The component is literally just a simple js file that has the image integrated (from the map) so I did not think I needed to show it but I can if needed. Also, I did block out my API key but the error is in the json/API. I know the issue is between setState and mapping.
import React, {useEffect, useState, Component} from 'react';
import './App.css';
import Mars from './Mars.js'
const App = () => {
const App_Key = "bSfujNx0oXZ7T5czBchcMbfLMg7dYdC9YOR7ZqJZ"
const [mars, setMars] = useState([]);
useEffect (() => {
getMars();
}, []);
const getMars = async () => {
const response = await fetch(`https://api.nasa.gov/mars-photos/api/v1/rovers/curiosity/photos?sol=1000&camera=fhaz&api_key=xxxxxxxxxxxx
const data = await response.json();
console.log(data.photos);
setMars(data.data);
}
return(
<div className="App">
<h1>Mars Rover</h1>
{mars.map(mar => (
<Mars
image={mars.data.photos.data.img_src}
/>
))}
</div>
);
};
The response structure shows that the path of img_sc is data.photos[i].img_src. You are trying to access it using data.data.data.photos.data.img_src.
At the place where the state of mars is being set, use data.photos instead of data.data
setMars(data.photos);
And inside the map function
{mars.map(photo=> (
<Mars image={photo.img_src} />
))}

const is 'undefined' after setting new value to it from an async api call

I have an application that calculates work shifts. One can add wishes for specific shifts, and they are automatically calculated. Backend works correctly and takes wishes into account, but when I call my api to get all wishes and try to print the output to web page, I get an error
TypeError: Cannot read property 'EmpId' of undefined
Here is my simplified React app
import React, {useState} from 'react'
import Wish from './components/wish'
const [shifts, setShifts] = useState('')
const [wishes, setWishes] = useState([])
const addWish = async (event) => {
event.preventDefault()
const wish = {
EmpId: selectedEmployee,
Shift: selectedShift,
Day: selectedDay
}
await wishService.postWish(wish) //Posts the new wish. Works, and is taken into account by backend.
setShifts(await shiftService.getAll()) //shiftService gets shifts as a string and works correctly, not necessary to implement here.
setWishes(await wishService.getAll() //Gets all wishes from backend
console.log(wishes) // Prints a correct-looking array of wishes. Example of wishes[0] 0: {id: 1, empId: 1, shift: 2, day: 3}
}
//...
return (
<div>
{wishes.map(wish =>
<Wish key={wish.id} //Bang. Here wishes is all of a sudden undefined and error pops.
EmpId={wish.EmpId}
Day={wish.Day}
WantedShift={wish.WantedShift}
</div>
Wish is a very simple module:
import React from 'react'
const Wish = ({ wish }) => {
return (
<div>
{wish.EmpId} , {wish.Day} , {wish.WantedShift}
</div>
)
}
export default Wish
Here is also my WishService, which I think should work fine. At least both console.log calls make reasonable output.
import axios from 'axios'
const baseUrl = 'https://localhost:5001/api/ShiftWishes'
const getAll = async () => {
const response = await axios.get(baseUrl)
const wishes = response.data
console.log(wishes)
return wishes
}
const postWish = async newObject => {
const response = await axios.post(baseUrl, newObject)
const wish = response.data
console.log(wish)
return wish
}
export default {getAll, postWish}
I have a feeling that the problem is something simple I just don't yet understand about async calls, but really cannot spot the problem since the calls seem to be working just fine, whole program worked fine until I wanted to print the wishes on screen. Thank you for your help!
The issue is with the Wish Component , you are passing EmpId, Day, WantedShift props whereas the Wish component is expected a wish object containing these values
Change the below code,
return (
<div>
{wishes.map(wish =>
<Wish key={wish.id} //Bang. Here wishes is all of a sudden undefined and error pops.
EmpId={wish.EmpId}
Day={wish.Day}
WantedShift={wish.WantedShift}
</div>)
Try doing the below:
return (
<div>
{wishes.map(wish =>
<Wish key={wish.id} wish={wish} />
</div>)
or change the Wish component
import React from 'react'
const Wish = ({ EmpId, Day, WantedShift }) => {
return (
<div>
{EmpId} , {Day} , {WantedShift}
</div>
)
}
export default Wish
The issue has nothing to do with scope, it has to do with timing and the React lifecycle. Calling any async functions on render is a huge no-no. You should call those only from useEffect(). Also your render could should be aware that the variables will be null the first time the component is mounted.

SWAPI request in React

I am trying to get SWAPI data from 'people' using react. I would ultimately like to retrieve the data and then set the people and create a card from the 10 people on page 1. When I console.log my response I am able to see the object returned. I am trying to set that using response.data.results (should contain people).
//full code:
import React, { useState, useEffect } from 'react';
import axios from "axios";
import Cards from "./components/Card"
function People() {
const [people, setPeople] = useState([]);
useEffect(() => {
axios.get('https://swapi.co/api/people/')
.then(res => {
//console.log(res);
setPeople(res.data.results)
})
.catch(err => {
console.log(`Data not received ${err}`)
})
}, [])
return (
<div className = "container">
{people.map((name, index) => {
return <Cards name={name} index={index}/>
})}
</div>
)
}
export default People;
When I console.log swPeople after using setswPeople I am returned an empty array.
Any ideas as to why the set is not giving me an array containing the 10 people on page one?
I see it working https://codesandbox.io/s/react-hooks-useeffect-frhmn
it take time to set the state , if we dont pass the second argument [] to useEffect you will see it is returning data correctly but that will cause the infinite loop , so we avoid that
import React, { useState, useEffect } from 'react';
import axios from "axios";
import Cards from "./components/Card"
function People() {
const [people, setPeople] = useState([]);
useEffect(() => {
axios.get('https://swapi.co/api/people/')
.then(res => {
//console.log(res);
setPeople(res.data.results)
})
.catch(err => {
console.log(`Data not received ${err}`)
})
}, [])
return (
<div className = "container">
{people.map((name, index) => {
return <Cards name={name} index={index}/>
})}
</div>
)
}
looks like this worked after all but it was taking close to 30s for me to see that info logged in console and I was being impatient
Have you tried to enter this url in your browser, https://swapi.co/api/people?
Because it seems the link is redirecting to another url while it needs to brign you back a JSON.
If you want to use SWAPI info replace you SWAPI to https://www.swapi.tech/api/people
it works well.
However I suggeust you to download the extension of JSONVue it will help you track your data with comfortable JSON view in your broweser.
And about the info of the 10 people you trying to get from SWAPI, when you'll open the browser with the new SWAPI adress, try to track the path you want to do in your code. You'll see the info you're trying to catch is leading to another API.

Resources