so i created a hook to fetch the ISS API. it works fine. but i am having difficulty displaying a specific part of the json that is returned.
my react fetch hook, the useEffect part
my display code
the code works and displays the first two tags, but when i add the 3rd with location.iss_position.longitude i get an undefined error
the console.dir of the json data
i have tried many variations of location.iss_position.longitude but nothing seems to work and a few google searches were unproductive. maybe my own fault for being able to accurately describe my problem with the correct technical language.
EDIT: heres my full code for fetch and display logic. i followed a tutorial and understand about 80% of it now. still learning
export const useFetchPosition = () => {
// define states for the hook
const [location, setLocation] = useState({})
const [loading, setLoading] = useState(false)
const [error, setError] = useState(null)
useEffect(() => {
// init loading and error states
setLoading(true)
setError(null)
// fetch api url
fetch(issUrl)
// return response as promise with json content
.then(res => res.json())
// return json promise, setLoading state, console log
.then(json => {
setLoading(false)
if (json) {
setLocation(json)
console.dir(json)
} else {
// this else prevents infinite loop
setLocation([])
}
})
// errors update state here
.catch(err => {
setError(err)
setLoading(false)
})
},[])
// return updated states for export to display
return { location, loading, error }
}
const Display = () => {
//call hook and hook data
const { location, loading, error } = useFetchPosition()
// loading and error
if (loading) return <div>Loading...</div>
if (error) return <div>{error}</div>
return (
<>
<h2 className="bg-gray-900 text-gray-300 text-center text-6xl">
{location.message}
</h2>
<h2 className="bg-gray-900 text-gray-300 text-center text-3xl">
response timestamp: {location.timestamp}
</h2>
<h2 className="bg-gray-900 text-gray-300 text-center text-3xl">
current latitude: {JSON.stringify(location) !== '{}' && location.iss_position.latitude}
</h2>
<h2 className="bg-gray-900 text-gray-300 text-center text-3xl">
current longitude: {JSON.stringify(location) !== '{}' && location.iss_position.longitude}
</h2>
</>
)
}
export default Display
Answer:
React isn't having difficulty displaying the JSON response; it's having trouble displaying your component before the response comes in, because you are trying to reference members of undefined objects.
Try putting JSON.stringify(location) !== '{}' && location.iss_position.latitude instead (presuming your default state, when using setState is {})
Alternatively you can define a default state in the same shape as the API's response
Explanation
This is normal Javascript behaviour.
You've assigned {} to location when you first called:
// I'm presuming you did something like this
let [location, setLocation] = setState({});
At this point, location is set to {}. You can, in any JS context, try to refer to members of an object that don't exist and you'll get undefined.
But when you do location.iss_position.longitude, you are trying to reference longitude on a member iss_position which is undefined - this will throw an error. You cannot reference members of undefined, but you can reference undefined members on a defined object.
Try running the following in your console:
let foo = {}; // Can't redefine window.location
console.log(foo); // {}
console.log(foo.iss_position); // undefined
console.log(foo.iss_position.longitude); // TypeError: location.iss_position is undefined
In fact, your console will tell you exactly that. The error your component is throwing specifically says:
location.iss_position is undefined
This is telling you that the object you are trying to reference (location.iss_position) is undefined at some point (before the API responds, for example)
Related
I'm working with React.js and I have the following problem:
import axios from "axios";
export default function Home() {
const [products, setProducts] = useState([]);
const ax = axios.create({ headers: { Accept: 'application/json' }});
function test() {
const res = ax.get("https://vtexstore.codeby.com.br/api/catalog_system/pub/products/search").then((response) => {
// expected the setProducts to be filled with the return of this request
setProducts(response.data);
});
}
test();
// and when I get here to see if the products have been filled, I get an empty array [ ]
console.log(products);
/*
as the products variable was not filled within the axios promise by setProducts,
there is no way to throw the products array here in the HTML to make a forEach or
a map to look cute together with the tags
*/
return (
<sup>how sad, with the product array empty, I can't put the data here '-'</sup>
);
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.2.0/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.2.0/umd/react-dom.production.min.js"></script>
See how the result comes out in the IDE console:
I'm in Visual Studio not knowing what to do, I'm new to ReactJS with NextJS and from an early age I've been trying to see if I could solve this problem, but without success.
What can I do to bring the products to the HTML page?
UPDATE: As per the solution below, I created a possible workaround that indicates a path that could have returned a solution
ax.get("https://vtexstore.codeby.com.br/api/catalog_system/pub/products/search/", {})
.then((response) => setProducts(response.data))
.catch((error) => {
console.log(error); // AxiosError {message: 'Network Error', name: 'AxiosError', ...}
console.log(error.status); // undefined
console.log(error.code); // ERR_NETWORK
});
useEffect(() => {
console.log(products);
}, []);
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/18.0.2/umd/react.production.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react-dom/18.0.2/umd/react-dom.production.min.js"></script>
and I'm getting the same error that I put in the comments of the first answer below:
but when I change the setProducts by the console.log to see if it returns the same result, this appears in the terminal where my next.js application is running
that:
ax.get("https://vtexstore.codeby.com.br/api/catalog_system/pub/products/search/", {})
.then((response) => console.log(response.data.length)) // returns the length of the products array
returns this when I update my app:
NOTE: That's why I'm not able to understand my application in Next.js. I'm following all the correct guidelines, writing the code perfectly using axios and when I run the application on the website it gives a network error and doesn't show exactly the amount of products that were displayed in the terminal where my application is running.
I've already configured all the request headers correctly, enabling CORS to allow external requests with other API's, and I still don't succeed in returning the data to my application's page.
Wrap the stuff you have to fetch products inside useEffect hook
useEffect(()=>{
const ax = axios.create({ headers: { Accept: 'application/json' }});
function test() {
const res = ax.get("https://vtexstore.codeby.com.br/api/catalog_system/pub/products/search").then((response) => {
// expected the setProducts to be filled with the return of this request
setProducts(response.data);
console.log(response.data)
});
}
test();
},[])
Then in your return of the component, you can use map on products array with null and undefined checks
Like
{products && products.map(product=>{})}
I am learning react and making a weather app. It is fetching API from open weather and assigns response to data and then setting value to city using setCity. But on first load the city varaible is undefined and when I console log out data it has all the JSON object.
const [city, setCity] = useState({})
useEffect(()=>{
getWeather()
},[setCity])
const getWeather = async ()=> {
const reqAPI = `http://api.openweathermap.org/data/2.5/weather?q=toronto&units=metric&appid=${API_KEY}`
const response = (await fetch(reqAPI)).json()
const data = await response
console.log(data)
setCity(data)
console.log(city)
}
console log data is ok giving all value but city is undefined on first load and crashes the app. Please help as I am not able to find a solution
Here is the console output both should be same but are not!
You can see after editing out the code I am still getting this error
line 20 and 23 console output
Fetch gives promise as output which needs to be handled with .then() i.e then() part is executed once promise once the promise is complete. Also add your state city to dependency array as stated below.
Update your useEffect like this
useEffect(() => {
const reqAPI = `http://api.openweathermap.org/data/2.5/weather?q=toronto&units=metric&appid=${API_KEY}`;
fetch(reqAPI)
.then((response) => {
console.log(response);
response = response.json();
console.log(response);
setCity(response);
})
.catch((e) => console.log(e));
}, [city]);
and drop getWeather function.
Have a look at promises here
Update:
Render your city component only if the city is not an empty object like this
{Object.keys(city).length !== 0 ? <YourCityComponent/> : <div></div>}
Here, i have added a check to not render when city is {} and in the above statement <YourCityComponent/> refers to your <City key={city.id} name={city.name} etc./>.
It can be done in multiple ways but this is the easiest on to understand.
Have a look at this too on how to check if your object is empty.
City being an empty object on the first load is exactly what is supposed to happen. Don't fix it, instead.. handle this state.
First, it's better to initialize the state with undefined:
const [city, setCity] = useState()
Then later in the component, handle this case:
return <div>Loading...</div>;
You should move your getWeather function to inside the useEffect hook. Also react state updates are asynchronous so when you're trying to console.log(city.main) right after you setCity there is no guarantee that the state has been updated. If you want to console.log when the state has been updated then you could use another useEffect with city in the dependency array.
Im trying to show an object's properties on a modal, but nothing seems to happen after i fetch it. I've tried without using the useEffect hook, and it does store the item but then i cant access the properties, i asked about it, and a user told me to use use Effect. But now, nothing seems to be stored...
This is my code:
import React, {useState, useEffect } from 'react';
const Modal = ({ handleClose, show, id }) => {
const showHideClassName = show ? "mod displayBlock" : "mod displayNone";
const [peliSeleccionada, setPeli] = useState([]);
useEffect(() => {
fetch(`http://localhost/APIpeliculas/api/pelicula/read_single.php/?ID=${id}`)
.then(res => res.json())
.then(
result => {
alert(result); //the alerts dont even pop up
setPeli(result);
alert(peliSeleccionada);
});
}, []);
return (
<div className={showHideClassName}>
<section className="mod-main">
<h5>EDITAR: </h5>
<label>
{ peliSeleccionada.Nombre }
</label>
<div className="btn-grupo">
<button type="button" className="btn btn-success btn-lg btn-block">Guardar cambios</button>
<button onClick={handleClose} type="button" className="btn btn-secondary btn-lg btn-block">Cerrar</button>
</div>
</section>
</div>
);
};
export default Modal;
The alerts i put inside my useEffect function dont even pop up, and i also get this error on the console as soon as i enter the page:
Uncaught (in promise) SyntaxError: Unexpected token < in JSON at position 0
Also I want to access my object's properties, which are: ID, Nombre, Categoria, and Director. Is this the correct way to do it? { peliSeleccionada.Nombre }
useEffect is run after the component renders, similarly to how componentDidMount works.
What this means, putting it very simply, is that the component will return and then fire the fetch.
There is an issue with your peliSeleccionada state, you declare it as an array but call peliSeleccionada.Nombre like if it was an object. This means that on first render it will print undefined for the peliSeleccionada.Nombre.
An approach to have this is to pair it with a loading state.
const Modal = () => {
const [loaded, setLoading] = useState(true);
const [peliSeleccionada, setPeli] = useState({});
useEffect( () => {
fetch()
.then(res => {
setPeli(res) // parse this accordingly
}) // or chain of thens if needed
.catch(err => {
setLoading(false);
console.log(err) // something failed in the fetch. You could have another state to mark that the fetching failed; close the modal, show an error, etc.
})
}, [])
if(!loaded) return 'Loading...'
return (<div>Data goes here</div>) // be careful if the fetch failed, it won't show data!
}
Last but not least, the error is happening in the fetch and the message states exactly that, that you are not catching it. If it is in the fetch call, the above code works. If it is in a parsing, it might require a try/catch around the useEffect
i try to fetch api json , here is the link https://api.myjson.com/bins/ut9kq
when i print the output before the loop it does get the data but after the list it give me error
"Unhandled Exception: NoSuchMethodError: The getter 'image' was called on null.
E/flutter (30730): Receiver: null
E/flutter (30730): Tried calling: image"
here is my code
List lists;
Future<List> getLists() async {
lists = new List();
await api.httpGet('bins/ut9kq').then((reponse) {
var data = jsonDecode(reponse.body);
print(data); // i get the json data => [{},{}..]
data.forEach((l) {
lists.add(ArticleModal().fromJson(l));
});
// print(lists[0].image);//Receiver: null
});
return lists;
}
You are using both approaches for future handling, .then callbacks and async and await. Try the following, you can wrap these around try/catch blocks for error handling.
Future<List<ArticleModal>> getLists() async {
lists = new List();
var response = await http.get('bins/ut9kq');
// a switch may be used for a wider range of codes
if (response.statusCode == 200) {
var decodedResponse = json.decode(response.body);
print(decodedResponse);
//if response is a collection
var listAricleModal = (decodedResponse as List).map((collectionElement) => ArticleModal.fromJson(collectionElement)).toList();
return listAricleModal;
}
//Your future is an empty collection
return [];
}
And to properly answer your question, image is called on null is quite obvious message.
At some point you have an image field, that object is not created. Probably is the object in the list, so two things may be happening:
List is empty, so nothing to call image on.
There is a problem when calling fromJson.
Either way, use the debugger and set breakpoints on each method first line to clearly understand what is happening.
If map function is tricky to debug, use a plain for loop until you know where the bug is.
Check out this series of videos from Google.
https://youtu.be/vl_AaCgudcY
Also official docs: https://dart.dev/codelabs/async-await
I am using the React Framework with TypeScript.
My Problem is that I am trying to access Data from a successfully received promise using the fetch-method. So that i can already see (in the browser console) that there is an array with the needed data containend in the promise. That's my browser console output: Chrome Console Output
The fetch is beeing executed as soon as the component mounts and saves the results in the state:
constructor(){
super();
this.processJSON = this.processJSON.bind(this);
this.state = {
buecherJSON : []
}
}
componentDidMount() {
fetch('http://localhost:8080/buecher/findAllByIsbnIsBefore?anzahl=2')
.then(results => {
this.setState({
buecherJSON : results.json()
});
})
.catch((error) => {
console.error(error);
});
}
In separate method I want to process the JSON formatted data to make an object out of it. But I can't figure out how to make that. So i far i got this (which is basically doing nothing):
processJSON(){
var buecherJSON = this.state;
console.log(Object.assign({},buecherJSON));
}
How can I map the received JSON to an accessible array in TypeScript?