React .map not rendering - javascript

I've done a API call to get some datas then store it in an array and do a .map in the return
This is the code if you guys have any ideas it's been 2 hours that i'm stuck on this :(
import {useEffect, useState} from 'react';
import {useParams} from "react-router-dom";
import axios from "axios";
const CharacterScreen = () => {
const params = useParams()
const [character, setCharacter] = useState([]);
const [starships, setStarships] = useState([]);
useEffect(() => {
axios.get(`https://swapi.dev/api/people/?search=${params.character}`)
.then((r) => {
setCharacter(r.data.results[0])
getStarships(r.data.results[0])
})
.catch((e) => console.log(e))
const getStarships = (data) => {
let array = []
data.starships.forEach(element => {
axios.get(element)
.then((r) => {
array.push(r.data)
})
.catch((e) => console.log(e))
})
console.log(array)
setStarships(array)
}
}, []);
console.log(starships)
return (
<div>
<p>{character.name}</p>
<p>{character.eye_color}</p>
<p>{character.birth_year}</p>
<p>{character.gender}</p>
<p>{character.created}</p>
<p>{character.edited}</p>
{starships.map((element) => {
console.log('ok')
return (
<p key={element.key}>{element.name}</p>
)
})}
</div>
)
}
This is the .log of starships :
This is my return :
Any help would be apréciated

Use spread operator :
useEffect(() => {
axios.get(`https://swapi.dev/api/people/?search=${params.character}`)
.then((r) => {
setCharacter(r.data.results[0])
getStarships(r.data.results[0])
})
.catch((e) => console.log(e))
const getStarships = (data) => {
let array = []
data.starships.forEach(element => {
axios.get(element)
.then((r) => {
array.push(r.data)
})
.catch((e) => console.log(e))
})
setStarships([...array]) <=== //spread opeator
}
}, []);

The code inside your forEach will run asynchronously. You would have to wait for all that data to be actually populated in your array. async/await pattern + Promise.all(..) would be a good bet here and can be done like so :-
const getStarships = async (data) => {
let array = await Promise.all(data.starships.map(element => {
return axios.get(element)
.then((r) => {
return r.data
})
.catch((e) => console.log(e));
}))
setStarships(array);
}
Currently in your code by the time you do setStarships(array), array will be empty i.e. [].
Check this codesandbox where it's working :-
Note :- Don't pay attention to element.replace code, thats just for making secure requests

You have a syntax error, you should replace your bracket with a parenthesis like following:
{starship && starships.map((element) => (//here
console.log('ok')
return (
<p key={element.key}>{element.name}</p>
)
)//and here)}

Related

Mapping data coming from API

I want to map the data for this app. I can't see the data in the browser window in Reactjs. I tried this:
import React, { useEffect, useState } from "react";
import "../css/Section.css";
const OfferSection = () => {
const [offer,setOffer] = useState([])
useEffect(() => {
const textdes = async () => {
const response = await fetch(`${process.env.REACT_APP_BASEURL}`).then(
(response) => response.json()
);
setOffer(response);
};
textdes();
},[])
return(
<div>
{offer.map((item) => {
{item.payload.map((ip) => {
return (
<img src={ip.data.section2.data[0].image} />
)
})}
})}
</div>
)
}
export default OfferSection;
I want data from this API:
http://192.168.1.175:5000/api/home
Write down the function outside of useEffect and then call it inside UseEffect.
console the response log to see data is comming from API or not
const textdes = async () => {
const response = await fetch(`${process.env.REACT_APP_BASEURL}`).then(
(response) => response.json()
);
console.log(response);
return response;
};
useEffect(() => {
textdes().then((res) => setOffer(res)).catch((err) => console.log(err))
},[]}

Mapping through a fetched array from firebase but nothing shows up even though the array is not empty [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 1 year ago.
I fetched an array of products from firebase with the normal way :
export const getUsersProducts = async uid => {
const UsersProducts = []
await db.collection('products').where("userID", "==", uid).get().then(snapshot => {
snapshot.forEach(doc => UsersProducts.push(doc.data()))
})
return UsersProducts
}
and the fetched array shows up in the dom normally, but when I tried to fetch it with onSnapshot method it didnt show up on the DOM even though in appeared in my redux store and when I console log it, it shows up normally.
export const getUsersProducts = uid => {
let UsersProducts = []
db.collection('products').where("userID", "==", uid).onSnapshot(querySnapshot => {
querySnapshot.docChanges().forEach(change => {
if (change.type === "added") {
UsersProducts.push(change.doc.data())
}
})
})
return UsersProducts
}
here is the code used to show it in the DOM
const MyProducts = () => {
const CurrentUserInfos = useSelector(state => state.userReducer.currentUserInfos)
const searchQuery = useSelector(state => state.productsReducer.searchQuery)
const myProducts = useSelector(state => state.productsReducer.usersProducts)
const dispatch = useDispatch()
const settingUsersProductList = async () => {
try {
const usersProducts = getUsersProducts(CurrentUserInfos.userID)
dispatch(setUsersProducts(usersProducts))
console.log(myProducts)
} catch (err) {
console.log(err)
}
}
useEffect(() => {
settingUsersProductList()
}, [CurrentUserInfos])
return (
<div className="my-products">
<div className="my-products__search-bar">
<SearchBar />
</div>
<div className="my-products__list">
{
Object.keys(myProducts).length===0 ? (<Loading />) : (myProducts.filter(product => {
if(searchQuery==="")
return product
else if(product.title && product.title.toLowerCase().includes(searchQuery.toLowerCase()))
return product
}).map(product => {
return(
<ProductItem
key={product.id}
product={product}
/>
)
}))
}
</div>
</div>
)
}
export default MyProducts
You are returning the array before promise is resolved hence its empty. Try this:
export const getUsersProducts = async uid => {
const snapshot = await db.collection('products').where("userID", "==", uid).get()
const UsersProducts = snapshot.docs.map(doc => doc.data())
return UsersProducts
}
For onSnapshot, add the return statement inside of onSnapshot,
export const getUsersProducts = uid => {
let UsersProducts = []
return db.collection('products').where("userID", "==", uid).onSnapshot(querySnapshot => {
querySnapshot.docChanges().forEach(change => {
if (change.type === "added") {
UsersProducts.push(change.doc.data())
}
})
return UsersProducts
})
}

API data not appearing in component but shows in console

I am making a rather simple API call to (https://api.punkapi.com/v2/beers) and displaying fetched data in the component, but somehow the data is not getting displayed on the page, but when I console log it the data is displayed correctly.
const Comp= () => {
const [item, setItem] = React.useState([]);
React.useEffect(() => {
fetch('https://api.punkapi.com/v2/beers')
.then((res) => res.json())
.then((data) => {
setItem(data);
})
.catch((err) => {
console.log(err);
});
}, []);
return (
<div>
{item.map((beer) => {
const { name, tagline } = beer;
<p>{name}</p>;
console.log(name);
})}
</div>
);
};
Issue
You don't return anything from your item mapping. Return the JSX you want to render (i.e. return <p>{name}</p>) and don't forget to add a React key to the mapped elements. Below I've simplified to an implicit return.
You should also remove the console log from the render return as "render" methods are to be pure functions without side-effects, such as console logging. Either log the fetch result in the promise chain or use an useEffect hook to log the updated state.
useEffect(() => console.log(item), [item]);
...
return (
<div>
{item.map(({ id, name }) => (
<p key={id}>{name}</p>
))}
</div>
);
You need to return the value from inside .map method like:
return (<p>{name}</p>)
You need to return the JSX elements in your map.
const Comp= () => {
const [item, setItem] = React.useState([]);
React.useEffect(() => {
fetch('https://api.punkapi.com/v2/beers')
.then((res) => res.json())
.then((data) => {
setItem(data);
})
.catch((err) => {
console.log(err);
});
}, []);
return (
<div>
{item.map((beer) => {
const { name, tagline } = beer;
return <p>{name}</p>;
console.log(name);
})}
</div>
);
};

API giving data in second render in React

I was trying to fetch api with react.js but on first render its gives nothing and the second render its gives data. This makes it so when I try to access the data later for an image I get an error, TypeError: Cannot read property 'news.article' of undefined, because it is initially empty. how can I solve this?
here is my code ..
import React, { useEffect, useState } from 'react';
const HomeContent = () => {
const [news, updateNews] = useState([]);
console.log(news);
useEffect(() => {
const api = 'http://newsapi.org/v2/top-headlines?country=us&category=business&apiKey=940c56bd75da495592edd812cce82149'
fetch(api)
.then(response => response.json())
.then(data => updateNews(data))
.catch((error) => console.log(error))
}, [])
return (
<>
</>
);
};
export default HomeContent;
There is no issue with the code itself, the output you receive is expected. However, you can render the content after it is retrieved as such
import React, { useEffect, useState } from 'react';
const HomeContent = () => {
const [news, updateNews] = useState([]);
const [isLoading, setIsLoading] = useState(true);
console.log(news);
useEffect(() => {
const api = 'http://newsapi.org/v2/top-headlines?country=us&category=business&apiKey=940c56bd75da495592edd812cce82149'
fetch(api)
.then(response => response.json())
.then(data => {
updateNews(data.articles);
setIsLoading(false);
})
.catch((error) => {
console.log(error);
setIsLoading(false);
})
}, [])
return (
<>
{isLoading ?
<p>Loading...</p> :
// Some JSX rendering the data
}
</>
);
};
export default HomeContent;

How to update an array using useState Hook

I've tried to fetch data from a URL and get the result as JSON format, then store not of the object result in my state. but it always returns an empty array.
const [genres, setGenres] = useState([]);
useEffect(() => {
const getGenres = async () => {
fetch("https://quote-garden.herokuapp.com/api/v2/genres")
.then((response) => response.json())
.then((data) => {
for (const g of data.genres) {
setGenres((oldGenres) => [...oldGenres, g]);
}
});
};
getGenres();
}, []);
Here is the code:
I don't see where the problem can be.
ps: I deleted the import so the code is more readable
import React, { useEffect, useState } from "react";
function App() {
const [quoteOfTheDay, setQuoteOfTheDay] = useState("");
const [authorOfQod, setAuthorOfQod] = useState("");
useEffect(() => {
const getQuoteOfTheDay = async () => {
fetch("https://quotes.rest/qod?language=en")
.then((response) => response.json())
.then((data) => {
const qod = data.contents.quotes[0].quote;
const author = data.contents.quotes[0].author;
setQuoteOfTheDay(qod);
setAuthorOfQod(author);
});
};
getQuoteOfTheDay();
}, []);
const [genres, setGenres] = useState([]);
useEffect(() => {
const getGenres = async () => {
fetch("https://quote-garden.herokuapp.com/api/v2/genres")
.then((response) => response.json())
.then((data) => {
for (const g of data.genres) {
setGenres((oldGenres) => [...oldGenres, g]);
}
});
console.log(genres); // genres always empty
};
getGenres();
}, []);
return (
<div className="app">
<Head quoteOfTheDay={quoteOfTheDay} author={authorOfQod} />
<div className="app__category">
<QuoteCategory genre="sport" />
</div>
</div>
);
}
export default App;
Thank you so much
I think it should work if you change
for (const g of data.genres) {
setGenres((oldGenres) => [...oldGenres, g]);
}
to
setGenres((oldGenres) => [...oldGenres, ...data.genres]);
Are you sure that
useEffect(() => {
const getGenres = async () => {
fetch("https://quote-garden.herokuapp.com/api/v2/genres")
.then((response) => response.json())
.then((data) => {
setGenres(data.genres);
});
};
getGenres();
}, []);
is not enough? :)
Up. If you began you can use async-await syntax till the end. It looks more neatly.
useEffect(() => {
const getGenres = async () => {
const response = await fetch("https://quote-garden.herokuapp.com/api/v2/genres");
const { genres } = await response.json();
setGenres(genres);
};
getGenres();
}, []);
you should put genresState as your dependency
const [genresState, setGenres] = useState([])
useEffect(() => {
const getGenres = async () => {
const response = await fetch("https://quote-garden.herokuapp.com/api/v2/genres");
const { genres } = await response.json();
setGenres(genres);
};
getGenres();
}, [genresState]);

Categories

Resources