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
Related
I have a Alice-Carousel in react where I am getting the items from an API.After fetching the data from API , I am updating the items array for the carousel but am getting the value of items as undefined. CryptoState is the context to prevent prop-drilling.
import React from 'react'
import { useEffect ,useState} from 'react';
import { CryptoState } from '../CryptoContext'
import { TrendingCoins } from '../api';
import axios from 'axios'
import AliceCarousel from 'react-alice-carousel';
import {Link} from 'react-router-dom'
const Carousel = () => {
const [trending,setTrending] = useState([]);
const {currency,setCurrency} = CryptoState();
useEffect(() => {
const {data}= axios.get(TrendingCoins(currency));
setTrending(data);
},[currency,trending])
// 0 pe 2 items dikhane hai, 512 size pe 4 items dikhane hai,
// thats all about responsiveness.
const responsives = {
0: {
items: 2
},
512: {
items: 4
}
}
const items= trending.map((coin) => {
return (
<>
<Link to={`/coins/${coin.id}`}/>
<img
className="carouselImages"
src={coin?.image}
height="80"
style={{marginBottom:10}}
/>
</>
)
})
return (
<AliceCarousel
infinite
mouseTracking
autoPlayInterval={1000}
animationDuration={1500}
disableDotsControls
responsive={responsives}
autoPlay
items={items}
/>
)
}
export default Carousel
useEffect(()=>{
const getData = async () => {
try{
const {data} = await axios.get(TrendingCoins(currency));
setTrending(data);
}catch{}
}
getData()
}, [currency, trending])
you are not waiting for the response, also you can just write async in useEffect arrow function
edit. : https://devtrium.com/posts/async-functions-useeffect
const {data}= axios.get(TrendingCoins(currency));
the problem is axios.get is a async call so basically your are not waiting for its result, you could async/await or promises
useEffect(async ()=>{
const response = await axios.get(TrendingCoins(currency));
setTrending(response.data);
},[currency,trending])
Axios is asynchronous meaning the App needs to wait for the data to be delivered. One of the way to do this is by using Thenables.
There are some problems with the useEffect() dependecies. If you add trending as a dependency there will be an infinite loop that will probable make the browser crash. This is because the useState hook re-renders the component and changes the state and useEffect triggers when a dependency value changes.
In the return you also need to make changes. If the App does not have the available data, it cannot show it. To solve this we need use conditional statements.
Take a look
import React from 'react'
import { useEffect ,useState} from 'react';
import { CryptoState } from '../CryptoContext'
import { TrendingCoins } from '../api';
import axios from 'axios'
import AliceCarousel from 'react-alice-carousel';
import {Link} from 'react-router-dom'
const Carousel = () => {
const [trending,setTrending]=useState([]);
const {currency,setCurrency}=CryptoState();
useEffect(()=>{
axios.get(TrendingCoins(currency))
.then((data) => {
setTrending(data)
})
.catch((error) => {
console.log(error)
})
},[currency])
const responsives={ //0 pe 2 items dikhane hai, 512 size pe 4 items dikhane hai,thats all about responsiveness.
0:{
items:2,
},
512:{
items:4,
}
}
const items = trending.map((coin)=>{
return (
<>
<Link to={`/coins/${coin.id}`}/>
<img className="carouselImages"
src={coin?.image}
height="80"
style={{marginBottom:10}}
/>
</>
)
})
if(trending === undefined) return (<p>Loading data....</p>)
else return (
<AliceCarousel
infinite
mouseTracking
autoPlayInterval={1000}
animationDuration={1500}
disableDotsControls
responsive={responsives} //responsive is to generate responsiveness....
autoPlay
items={items}
/>
)
}
export default Carousel
I can't render props from useContext because it returns undefined before desired object. I can't seem to find any solution to my problem.
This is the child element I'm trying to render:
const Reviews = ({reviews}) => {
return (
<div className={styles['review__card']}>
{reviews.map((review) => {
return(
<div className={styles['review__card__item']}>
<div className={styles['card__item__meta']}>
<span>{review.name}</span>
<span><StarRating rating={review.rating}/></span>
</div>
<div className={styles['card__item__p']}>
<p>{review.revew}</p>
</div>
</div>
)})}
</div>
)
}
export default Reviews
This is Parent Element:
import React, { useContext, useEffect } from 'react'
import { useParams } from 'react-router-dom'
import { RestaurantsContext } from '../context/RestaurantsContext';
import Wrapper from '../components/Wrapper'
import Header from '../components/Header'
import Reviews from '../components/Reviews'
import AddReview from '../components/AddReview'
import RestaurantFinder from '../apis/RestaurantFinder';
const RestaurantDetailPage = () => {
const {id} = useParams()
const {selectedRestaurant, setSelectedRestaurant} = useContext(RestaurantsContext)
useEffect(()=> {
const fetchDate = async () => {
try {
const response = await RestaurantFinder.get(`/${id}`)
setSelectedRestaurant(response.data.data)
}
catch (err) {console.log(err)
}
}
fetchDate()
}, [])
console.log(selectedRestaurant.reviews)
return (
<Wrapper>
<Header title={ 'RestaurantDetailPage' }/>
<div>{selectedRestaurant && (
<>
<Reviews reviews={selectedRestaurant.reviews}/>
<AddReview/>
</>
)}</div>
</Wrapper>
)
}
export default RestaurantDetailPage
Whenever I console.log(selectedRestaurant.reviews) it gives me undefined and then it gives me object query. I assume that .map() is getting an error because it is trying to render that first argument which is undefined
Here is Context js
import React, {useState, createContext} from 'react';
export const RestaurantsContext = createContext();
export const RestaurantsContextProvider = props => {
const [restaurants, setRestaurants] = useState([])
const [selectedRestaurant, setSelectedRestaurant] = useState([])
const addRestaurants = (restaurant) => {
setRestaurants([...restaurants, restaurant]);
}
return (
<RestaurantsContext.Provider value={{restaurants, setRestaurants, addRestaurants, selectedRestaurant, setSelectedRestaurant }}>
{props.children}
</RestaurantsContext.Provider>
)
}
I have found the issue and solved it though I'm not entirely sure how it works.
const [selectedRestaurant, setSelectedRestaurant] = useState([])
default useState value should be null using useState(null)
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;
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}/>
I've retrieved datas from my database to the Recipes component. now, I'm trying to pass those datas into the RecipeList component. However, I got just the bullet points into the RecipeList component and for some reason the Recipes component return only the element " title = {recipe.title} "
I'm just starting out programming. I would be pleased if someone can help me.
Recipes
import React, {useState, useEffect} from 'react'
import axios from 'axios'
import RecipeList from '../pages/espaceUser/RecipeList'
export default function Recipes(props) {
const [recipes, setRecipes] = useState([])
const [test] = useState("text")
useEffect(() => {
const id = props.match.params.id
const getRecipes = async () => {
const url = `http://localhost:8000/user/recipes/${id}`
const result = await axios.get(url)
setRecipes(result.data)
console.log('test', result.data);
}
getRecipes()
},[])
return (
<div>
{recipes.map(recipe => (
<RecipeList
key={recipe.id}
title={recipe.title}
materiel={recipe.materiel}
ingredient={recipe.ingredient}/>
))}
</div>
)
}
RecipeList
import React from 'react'
export default function RecipeList(props) {
return (
<div>
<ul>
<li>{props.title}</li>
<li>{props.materiel}</li>
<li>{props.ingredient}</li>
</ul>
</div>
)
}
It seems to me that it is not a problem with the syntax or structure of your code, if it's rendering the title at least it means that everything is working fine. I would suggest looking at react dev tools in chrome and check out if the components have all the props they are supposed to have