I am rendering a product list from dummyjson
getting response from api
but showing products.map() is not a function
const fetchData = async () => {
const response = await fetch("https://dummyjson.com/products");
const data = await response.json();
return setProducts(data);
}
useEffect(() => {
fetchData();
},[])
console.log(products)
return (
<div>
<ul>
{products.map((product, index) => {
return (
<li key={index}>
<h2>{product.title}</h2>
</li>
);
})}
</ul>
</div>
)
The api returns an object with a property products which contains the products array, so you need to do
{products.products.map((product, index) => {
Alternatively, you could store just the products array in state like so, and you can keep your existing map code.
return setProducts(data.products);
Your data is an object. What you want to do is extract products from the JSON response, so in fetchData method you should call: setProducts(data.products).
Related
firebase SORE where in fetch my database from fire store but when I try to render it, I get an empty array
I'm trying to implement a search where user can either for an item on the array and will render
I am new to react JavaScript . I want to create a search page for my web application project in which there will be a form using which the data can be fetched using fire store. Now i have fetched that data but I'm getting an empty array
export const handleFetchProduct = (productid) => {
return new Promise((resolve, reject) => {
firestore
.collection('products')
.doc(productID)
.get()
.then(snapshot => {
if (snapshot.exists) {
resolve({
...snapshot.data(),
documentID: productID
});
}
})
.catch(err => {
reject(err);
})
})
}
.Product result
this is where user would click and it would be rendered
const map State = ({products Data}) =>({
products:productsData.products
})
const Product Result = ({}) =>{
const dispatch = useDispatch()
const {products} = use Selector (map State)
console.log ('product RESULT', products)
useEffect(()=>{
dispatch (
fetchProductsStart()
);
}, []);
if (!Array.isArray(products)) return null
if(products.length < 1){
return (
<div className="products">
<p>
No search in the results
</p>
</div>
)
}
return (
<div>
<h1>Browse product</h1>
{products.map((product,index)=>{
const {productName,productThumbnail,productPrice} = product;
if(!productThumbnail || !productName || typeof productPrice === 'undefined' ) return null
return(
<div key={index}>
{productName}
{productPrice}
</div>
)
}
)}
</div>
)
}
export default ProductResult
I'm using react and trying to fetch data from this API
https://6033c4d8843b15001793194e.mockapi.io/api/locations
I want to get the name, but it is not loading anything. How do i debug that and see what part of my code is working and what isn't?
function Card() {
const url = "https://6033c4d8843b15001793194e.mockapi.io/api/locations";
const [locations, setLocations] = useState(null);
useEffect(() => {
axios.get(url)
.then(response => {
setLocations(response.data)
})
}, [url])
if(locations) {
return (
<div>
<h1>Acme HQ</h1>
<p>{locations.id}</p>
</div>
)
}
return (
<div>
<h1>error</h1>
</div>
)
}
This is my code, it doesn't throw any error but it also doesn't output anything.
I want to retrieve the name or the usercount from that API
Because the api return an array of object. So you can get an id of item in the array like this:
{locations?.[0].id}
To render items from array. You can using map: https://reactjs.org/docs/lists-and-keys.html
I am building Weather App, my idea is to save city name in localStorage, pass a prop to child component, then iterate using map and display each in seperate child of the first child
The problem is that displayed data doubles/triples on render(depending on component when render occurs) so when I have for example city London and add city Berlin it will render:
London,London,Berlin
The problem is not in AddCity component, it's working correctly but in this mix of asynchronous setState/fetching and maping
Please see the code below
App(parent component)
const App = () => {
const [cities, setCities] = useState([]);
const addCity = (newCity)=>{
console.log('adding')
setCities([...cities, newCity]);
let cityId = localStorage.length;
localStorage.setItem(`city${cityId}`, newCity);
}
useEffect(() => {
loadCityFromLocalStore()
}, [])
const loadCityFromLocalStore =()=>{
setCities([...cities, ...Object.values(localStorage)])
}
return (
<div>
<Header />
<AddCity addCity={addCity}/>
<DisplayWeather displayWeather={cities}/>
</div>
)
}
DisplayWeather (first child)
const DisplayWeather = ({displayWeather}) => {
const apiKey = '4c97ef52cb86a6fa1cff027ac4a37671';
const [fetchData, setFetchData] = useState([]);
useEffect(() => {
displayWeather.map(async city=>{
const res =await fetch(`http://api.openweathermap.org/data/2.5/weather?q=${city}&units=metric&appid=${apiKey}`)
const data = await res.json();
setFetchData((fetchData=>[...fetchData , data]));
})
}, [displayWeather])
return (
<>
{fetchData.map(data=>(
<ul>
<Weather
data={data}/>
</ul>
))}
</>
)
}
Weather component
const Weather = ({data}) => {
return (
<li>
{data.name}
</li>
)
}
It looks like the problem comes from calling setFetchData for cities that you already added previously.
One easy way to fix it would be to store fetch data as an object instead of a dictionary so that you just override the data for the city in case it already exists (or maybe even skip the fetch as you already have the data).
For example:
const [fetchData, setFetchData] = useState({});
useEffect(() => {
displayWeather.map(async city=>{
const res = await fetch(`http://api.openweathermap.org/data/2.5/weather?q=${city}&units=metric&appid=${apiKey}`)
const data = await res.json();
setFetchData((fetchData=> ({...fetchData, [city]: data})));
})
}, [displayWeather])
Then, to map over fetch data you can just use Object.values:
return (
<>
{Object.values(fetchData).map(data=>(
<ul>
<Weather
data={data}/>
</ul>
))}
</>
)
If you want to skip already fetched cities you can do something like this instead:
useEffect(() => {
displayWeather.map(async city=>{
if (!fetchData[city]) {
const res = await fetch(`http://api.openweathermap.org/data/2.5/weather?q=${city}&units=metric&appid=${apiKey}`)
const data = await res.json();
setFetchData((fetchData=> ({...fetchData, [city]: data})));
}
})
I am trying to get data from the backend and display the data in the frontend. To do that I tried this code.
function Posts() {
const [notes, getNotes] = useState([]);
useEffect(()=>{
getAllNotes();
}, []);
const getAllNotes = async () => {
await axios.get(`/buyerPosts`)
.then ((response)=>{
const allNotes=response.data.existingPosts;
getNotes(allNotes);
})
.catch(error=>console.error(`Error: ${error}`));
}
console.log(notes);
const buyerId=(localStorage.getItem("userId"));
console.log(buyerId);
const [offers, getOffers] = useState([]);
useEffect(()=>{
getAllOffers();
}, []);
const getAllOffers = async () => {
await axios.get(`/viewPendingSellerOffers`)
.then ((response)=>{
const allNotes=response.data.existingOffers;
getOffers(allNotes);
})
.catch(error=>console.error(`Error: ${error}`));
}
console.log(offers);
const wasteItem = offers?.filter(wasteItem => wasteItem.status==='accepted' && wasteItem.buyerId===buyerId && wasteItem.wasteItemsListId==='completePost');
console.log(wasteItem);
return(
<main className="grid-b">
{notes.map((note,index)=> {
if(note._id===wasteItem.postId)
return (
<article>
<div className="text-b">
<h3>Post ID: {index + 1}</h3>
<p>Location: {note.address}</p>
<p>Post Type: {note.postType}</p>
<p>Address: {note.address}</p>
<p>Telephone No: {note.contact}</p>
</div>
</article>
);
})}
</main>
);
}
export default Posts;
Hare, I call the first API and get a length 7 array of objects. This is an image of this result.
Then I call a second API and get a length 6 array of objects. This is an image of this result.
Then I try to filter second API call results like this const wasteItem = offers?.filter(wasteItem => wasteItem.status==='accepted' && wasteItem.buyerId===buyerId && wasteItem.wasteItemsListId==='completePost'); and I get length 2 array of objects as the result of this filter function.
Then I try to map the first API call data in a map function. To do that I used this condition if(note._id===wasteItem.postId). But this map function is not working. Maybe it does not work because wasteItem is an array of objects. How do I solve this problem?
wasteItem is an array of objects, but you treated it as object here if(note._id===wasteItem.postId). You would need to iterate through wasteItem array first, or use find().
{notes.map((note,index)=> {
if(wasteItem.find(o=>o.postId === note._id) !== undefined)
return (
<article>
...
</article>
);
})}
I'm trying to add filter functionality to my project. From a list of entries with different languages, an array of all languages is created. The user should be able to click a language and have React filter to only show entries with that language. However, I can't seem to update the entries state properly when running the filterIt function. If I console.log entries after running setEntries(filtered), the result is the same.
const Archive = () => {
const [entries, setEntries] = useState([]);
let dreamFilter = [];
//get all entries from firestore
useEffect(() => {
const unsubscribe = firebase
.firestore()
.collection("entries")
.onSnapshot((snapshot) => {
const newEntries = snapshot.docs.map((doc) => ({
id: doc.id,
...doc.data(),
}));
setEntries(newEntries);
});
return () => unsubscribe();
}, []);
//after entries are loaded, create filter of all languages for 'dream'
if (entries.length > 0) {
const categoryMap = Object.values(entries)
.reduce(
(concatedArr, item) => concatedArr.concat(Object.entries(item)),
[]
)
.reduce((result, [category, values]) => {
result[category] = result[category] || [];
result[category] = result[category].concat(values);
return result;
}, {});
dreamFilter = categoryMap.dream.filter(
(item, pos) => categoryMap.dream.indexOf(item) === pos
);
}
function filterIt(value) {
const filtered = entries.filter(entry => ({
...entry,
filtered: entry.dream.includes(value)
}));
console.log("filtered results = " + JSON.stringify(filtered));
setEntries(filtered);
return filtered;
}
return (
<>
<Navigation />
<ul>
{dreamFilter.map((language, i) => (
<li key={i}>
<a href="/" onClick={(value) => { filterIt(value); value.preventDefault(); }}>{language}</a>
</li>
))}
</ul>
<ArchiveContainer>
{entries.map((entry) => (
<div key={entry.id}>
<a href={"/entry/" + entry.id}>
<h5>{entry.id}</h5>
<p>{entry.dream}</p>
</a>
</div>
))}
</ArchiveContainer>
</>
);
}
Filter method should return either true or false. Read more here.
If you want to convert one array to an array of another object, then use map.
You need to modify filter method to be like this:
const filtered = entries.filter(entry => entry.dream.includes(value));
In functional component you can't update states directly.
assuming here you are trying to add filtered: true/false also in entries array.
array.filter is for adding or removing the object from array by returning true/false.
function filterIt(value) {
setEntries(entryList => entryList.map(item => ({
...item,
filtered: item.dream.includes(value)
})));
}