Im building a react app that fetches a random food data from spoonacular.com. Im trying to display the title name of the food on the page but it doesn't show up and also why does it keep fetching a bunch of different data as shown in the picture of the console.log even though I specified the number of data to fetch as 1 in the URL
This is my Home.js
import React, { useEffect, useState } from "react";
import axios from "axios";
import Recipe from "../components/Recipes";
const URL = `https://api.spoonacular.com/recipes/random?apiKey=${APIKey}&number=1`;
function Home() {
const [food, setFood] = useState({});
useEffect(() => {
axios
.get(URL)
.then(function (response) {
setFood(response.data);
console.log(food);
})
.catch(function (error) {
console.warn(error);
});
}, [food]);
return (
<main>
<Recipe recipeList={food} />
</main>
);
}
export default Home;
and this is my Recipe.js component
import React from "react";
function Recipe({ recipeList }) {
return (
<div className="recipeCard">
<h1>{recipeList.title}</h1>
</div>
);
}
export default Recipe;
and this is the picture of the console when I log the results fetched from the API (they're all different food datas but I only wanted to fetch 1 food data and display it on the page)
That's right, you get 1 random recipe, but useEffect works every time you update the food state, so you have an infinite loop. Just remove food from useEffect dependency. It's also better to check if recipeList exists so you don't get a missing title error
This should work as expected:
Home.js:
import React, { useEffect, useState } from "react";
import axios from "axios";
import Recipe from "../components/Recipes";
const URL = `https://api.spoonacular.com/recipes/random?apiKey=${APIKey}&number=1`;
function Home() {
const [food, setFood] = useState(null);
useEffect(() => {
axios
.get(URL)
.then(function (response) {
setFood(response.data);
console.log(food);
})
.catch(function (error) {
console.warn(error);
});
}, []);
return (
<main>
<Recipe recipeList={food} />
</main>
);
}
export default Home;
Recipe.js:
import React from "react";
function Recipe({ recipeList }) {
if(!recipeList) return <></>
return (
<div className="recipeCard">
<h1>{recipeList?.title}</h1>
</div>
);
}
export default Recipe;
Related
I'm trying to pass a JSON object (id) returned from an API call to another component via props and use that object(id) to fetch more data from a different endpoint. The problem is, when i pass the prop using object literal to the api, it gives an error undefined but when i console log the object(id) it works fine. What could be the issue? Just started learning React.
component passing object as prop
import axios from "axios";
import React, { useEffect, useState } from "react";
import { useParams } from "react-router-dom";
import Cast from "./Cast";
const DetailsView = () => {
const { id } = useParams();
const [details, setDetails] = useState([]);
useEffect(() => {
axios
.get(
`https://api.themoviedb.org/3/movie/${id}?api_key=<<api_key>>&language=en-US`
)
.then((response) => {
setDetails(response.data);
});
}, []);
return (
<div className="w-full h-[650px] text-white">
<<bunch of code>>
<Cast id={details?.id}/>
</div>
);
};
export default DetailsView;
component receiving prop
import React, { useState, useEffect } from "react";
import axios from "axios";
const Cast = (props) => {
const [cast, setCast] = useState([]);
const sid = props.id;
useEffect(() => {
axios
.get(
`https://api.themoviedb.org/3/movie/${sid}/credits?api_key=<<api_key>>&language=en-US`
)
.then((response) => {
setCast(response.data.cast);
console.log(response.data.cast);
});
}, []);
console.log(sid);
return (
<div className="absolute">
{cast && cast.map((item, index) => <p className="">{item.name}</p>)}
<p>{sid}</p>
</div>
);
};
export default Cast;
It doesn't work initially but when I edit the code, since the change is happening live, it fetches the data but when I refresh the page, Axios reports an error 404
xhr.js:220 GET https://api.themoviedb.org/3/movie/**undefined**/credits?api_key=56fbaac7fd77013cc072d285a17ec005&language=en-US 404
Your id property does not exist until the API call is completed, and there is a rerender after setDetails.
You can check if id exists and based on that render your Card component. Also, looks like details is an object not an array, so I changed the useState statement to reflect that.
import axios from "axios";
import React, { useEffect, useState } from "react";
import { useParams } from "react-router-dom";
import Cast from "./Cast";
const DetailsView = () => {
const { id } = useParams();
const [details, setDetails] = useState({});
useEffect(() => {
axios
.get(
`https://api.themoviedb.org/3/movie/${id}?api_key=<<api_key>>&language=en-US`
)
.then((response) => {
setDetails(response.data);
});
}, []);
return (
<div className="w-full h-[650px] text-white">
<<bunch of code>>
{details?.id && <Cast id={details?.id}/>}
</div>
);
};
export default DetailsView;
I first make a request to a MongoDB server to get data from a database, all asynchronously and return a promise in App.js.
Then I pass that as a prop in my Card.js component and use .then() to get the data and push it into a new array. (I'm not sure if this is the best way to do this)
Right now I'm trying to display the names in the data dynamically using an MUI Grid, I am having problems as it shows that the data is in my array but I get no Cards on the UI. What am I doing wrong?
Card.js
import * as React from 'react';
import Grid from '#mui/material/Grid';
import RoomCard from './RoomCard'
import { useState } from 'react';
export default function Card({rooms}){
const [loading, setLoading] = useState(false);
let roomData = [];
rooms.then(roomNames => {
roomNames.map(room => roomData.push(room));
})
console.log(roomData);
return(<Grid container spacing={2}>
{roomData.map(room =>
<Grid item key={room} xs ={4}>
<RoomCard name = {room.name} />
</Grid>
)}
</Grid>
);
}
App.js
import './App.css';
import Navbar from './components/NavBar';
import AddRoom from './components/AddRoom'
import RoomCard from './components/RoomCard'
import Grid from '#mui/material/Grid';
import Cards from './components/Cards'
function App() {
let rooms = getRecords();
return (
<div className="App">
<Navbar/>
<AddRoom/>
<Cards rooms = {rooms} />
</div>
);
}
async function getRecords() {
const response = await fetch(`http://localhost:5000/room/`);
if (!response.ok) {
const message = `An error occured: ${response.statusText}`;
window.alert(message);
return;
}
const rooms = await response.json();
return rooms;
}
export default App;
On my opinion App.js should be Higher order component (HOC) for Card.js so that Card.js is easily resusable for each room as your code may have it, the App.js should contain the loading controller. And you cannot call getRecords sync except inside an async and await function and you can use it inside a useEffect function since you are using function react function component, your code should be like this now
import React,{useEffect,useState} from 'react'
import './App.css';
import Navbar from './components/NavBar';
import AddRoom from './components/AddRoom'
import RoomCard from './components/RoomCard'
import Grid from '#mui/material/Grid';
import Cards from './components/Cards'
function App() {
const [loading,setLoading] useState(false);
const [rooms, setRooms] useState([]);
useEffect(()=>{
async fetchRooms(){
try{
setLoading(true)
const fetchedRooms = await getRecords();
setRooms(fetchedRooms);
setLoading(false)
}catch{
setLoading(false)
}
}
fetchRooms();
},[])// the empty array is used to pass value that will make this function to be called if they changed, since its empty this useffect only gets called when component is mounted
return (
<div className="App">
{ loading && (<p>loading.....</p>) }
<Navbar/>
<AddRoom/>
<Cards rooms = {rooms} />
</div>
);
}
async function getRecords() {
const response = await fetch(`http://localhost:5000/room/`);
if (!response.ok) {
const message = `An error occured: ${response.statusText}`;
window.alert(message);
return;
}
const rooms = await response.json();
return rooms;
}
export default App;
And inside your card.js you should have something like this
import * as React from 'react';
import Grid from '#mui/material/Grid';
import RoomCard from './RoomCard'
import { useState } from 'react';
export default function Card({rooms}){
return(<Grid container spacing={2}>
{rooms.map(room =>
<Grid item key={room} xs ={4}>
<RoomCard name = {room.name} />
</Grid>
)}
</Grid>
);
}
This makes sure your card.js is clean
Im making a project where I fetch an image of a recipe card from https://spoonacular.com and I want it displayed on my react.js app. For some reason I can't get the API data from displaying on the page when I run it. Please help Im really stuck. I keep getting the error that recipeList is undefined in Recipe.js but I thought it was defined?
This is my Home.js:
import React, { useEffect, useState } from "react";
import axios from "axios";
import Recipe from "../components/Recipes";
const URL = `https://api.spoonacular.com/recipes/716429/information?apiKey=${APIKey}&includeNutrition=false`;
function Home() {
const [food, setFood] = useState();
useEffect(() => {
if (food) {
axios
.get(URL)
.then(function (response) {
const recipeList = response.data;
setFood(recipeList);
})
.catch(function (error) {
console.warn(error);
});
}
}, [food]);
return (
<main>
<Recipe recipeList={food} />
</main>
);
}
export default Home;
this is my Recipe.js
import React from "react";
function Recipe({ recipeList }) {
return (
<div className="Recipe">
<div>{recipeList.title}</div>
<img src={recipeList.image} />
</div>
);
}
export default Recipe;
you need initializing empty
const [food, setFood] = useState({});
and in useEffect evaluate if food is empty
useEffect(() => {
const getData=()=>{
axios
.get(URL)
.then(function (response) {
const {data} = response;
setFood(data);
})
.catch(function (error) {
console.warn(error);
});
}
if(!food){ // validate if food is empthy to get data (food)
getData()
}
}, []); // here is not necesary use food, because never happen anything with that variable
The response example can be seen here.
To call that using axios:
import React, { useEffect, useState } from "react";
import axios from "axios";
import Recipe from "../components/Recipes";
const URL = `https://api.spoonacular.com/recipes/716429/information?apiKey=${APIKey}&includeNutrition=false`;
function Home() {
const [food, setFood] = useState({});
useEffect(() => {
// You can add any if-else statement here
// but you can also do the fetch without it
axios
.get(URL)
.then(function (response) {
setFood(response.data);
})
.catch(function (error) {
console.warn(error);
});
}, []);
return (
<main>
<Recipe recipeList={food} />
</main>
);
}
export default Home;
And based on the response, your Recipe.js should working properly.
Im building an app where I want to take api data from https://www.thecocktaildb.com to allow for users to search for a cocktail drink and it will fetch data from the api source to display the name of the drink on the page. I don't know why its giving me an error of "Uncaught TypeError: drinkList.drinks is undefined" because if you look at the screenshot I included of what the JSON data looks like, it should be correct?
This is my Home.js
import React, { useEffect, useState } from "react";
import axios from "axios";
import Drinks from "../components/Drinks";
function Home() {
const [drinkName, setDrinkName] = useState();
const drinksURL = `https://www.thecocktaildb.com/api/json/v1/1/search.php?s=${drinkName}`;
function handleChangeDrink(e) {
setDrinkName(e.target.value);
}
const getDrink = () => {
axios
.get(drinksURL)
.then(function (response) {
setDrinkName(response.data);
console.log(drinksURL);
})
.catch(function (error) {
console.warn(error);
});
};
return (
<main className="App">
<section className="drinks-section">
<input
type="text"
placeholder="Name of drink (e.g. margarita)"
onChange={handleChangeDrink}
/>
<button onClick={getDrink}>Get a Drink Recipe</button>
<Drinks drinkList={drinkName} />
</section>
</main>
);
}
export default Home;
and this is my Drinks.js component
import React from "react";
function Drinks({ drinkList }) {
if (!drinkList) return <></>;
return (
<section className="drinkCard">
<h1>{drinkList.drinks[0].strDrink}</h1>
</section>
);
}
export default Drinks;
This is a screenshot of the JSON data:
You should define the new variable for drink list
const [drinkList, setDrinkList] = useState([]);
And you should assign your response to this variable here (instead of assigning drinkName):
const getDrink = () => {
axios
.get(drinksURL)
.then(function (response) {
setDrinkList(response.data);
console.log(drinksURL);
})
.catch(function (error) {
console.warn(error);
});
};
Weather.JS File
import { useEffect, useState } from "react"
import axios from 'axios'
import WeatherDisplay from './WeatherDisplay'
const Weather = ({capital, params}) => {
const [weather,setWeather] = useState([])
useEffect(async () => {
const result = await axios.get('http://api.weatherstack.com/current', {params})
console.log(result.data)
setWeather(result.data)
},
[params])
return(
<div>
<h2>Weather in {capital}</h2>
<WeatherDisplay current={weather.current}/>
</div>
)
}
export default Weather
WeatherDisplay.js File
const WeatherDisplay = ({weather}) => {
console.log(weather.current.temperature)
return (
<h1>{weather.current.temperature}</h1>
)
}
export default WeatherDisplay
Having issues display the data when i use {weather.current.temperature}, it keeps giving me an error pointed at temperuture saying it isnt defined but its apart of the data
You are passing weather.current as props. While the child component is expecting weather as prop. So, what you end up doing is weather.current.current.temperature which is undefined because it doesn't exist. Just pass weather to the child prop.
Make this change when calling your child component.
<WeatherDisplay weather={weather}/>