I am using the NASA API to grab pictures of Mars taken by the Mars Rover. Currently, my code works with fetching the pictures however, I want it to be more dynamic. My code:
import React, { useEffect, useState } from "react";
import NavBar from "./NavBar";
const apiKey = process.env.REACT_APP_NASA_API_KEY;
function MarsPhoto() {
const [data, setData] = useState('null')
const [solDay, setSolDay] = useState('')
const apiUrl = `https://api.nasa.gov/mars-photos/api/v1/rovers/curiosity/photos?sol=${solDay}&camera=fhaz&api_key=${apiKey}`
const fetchPhotoData = (event) => {
if(event.key === 'Enter') {
fetch(apiUrl)
.then((response) => response.json())
.then((data) => setData(data))
}
}
useEffect(() => {
fetchPhotoData()
}, [])
return(
<>
<NavBar/>
<div className="sol-search">
<input
value={solDay}
onChange={event => setSolDay(event.target.value)}
placeholder="Enter a Sol Day"
type="text"/>
</div>
<div className="image-fhaz">
<img src={data.photos ? (data.photos.length !== 0 ? data.photos["0"]["img_src"] : 'https://www.ncenet.com/wp-content/uploads/2020/04/No-image-found.jpg') : 'null'}
alt="Pitcure"/>
</div>
</>
)
}
export default MarsPhoto;
When I say I want it to be dynamic I want the user to enter a 'solDay' and the API will show the image based on that sol day. I already have the 'solDay' parameter in the API. I have used a key handler so when I enter the number it will make the API call and return the image. I have the input with the event, however, it is throwing an "MarsPhoto.js:14 Uncaught TypeError: Cannot read properties of undefined (reading 'key')", I am not sure why? Rather than using fetch, would it be better to use Axios? I would prefer to use fetch as I am more familiar with this. What can I do?
First, you should catch a potentiel error response from the api. Second, you ask an event param in your fetchPhotoData function, you call it in the useEffect, it's mean at the first load of your component, your function will run but, there is no event params and your function doesn't have a shield for undefined params...
Take a look on bellow code, it should help you. :)
const fetchPhotoData = (event) => {
if (!event?.key) {
return console.info("[fetchPhotoData] : no event.key params");
}
if (event.key === "Enter") {
fetch(apiUrl)
.then((response) => response.json())
.then((data) => setData(data))
.catch((e) => console.error("[fetchPhotoData] error : ", e));
}
};
Edit :
The on change, set a new data on a useEffect, but you don't listen this change, so, your useEffect doesn't mount again, you should re-write your useEffect like this :
const fetchPhotoData = useCallback(
(event) => {
... current code
},
[apiUrl]
);
useEffect(() => {
fetchPhotoData();
}, [fetchPhotoData]);
apiURL is listened by the dependecies array of your useCallback function, and this is listenable by useEffect properly.