I have 2 APIs, one call the products and the other one call the image of the products.
Products API: https://inventory.dearsystems.com/ExternalApi/v2/Product
The second API is required call the ID of the products
Image API: https://inventory.dearsystems.com/ExternalApi/v2/product/attachments?ProductID=
How can I call the second one to show the image.
Here is my code:
import axios from "axios";
import { useEffect, useState } from "react";
import { SingleContent } from "../../components/SingleContent/SingleContent";
export const All = () => {
const [content, setContent] = useState([]);
const fetchAllProducts = async () => {
const { data } = await axios.get('https://inventory.dearsystems.com/ExternalApi/v2/Product',{
headers: {
"api-auth-accountid": process.env.REACT_APP_API_ID,
"api-auth-applicationkey": process.env.REACT_APP_API_KEY
}
});
console.log(data.Products);
setContent(data.Products)
}
useEffect(() =>{
fetchAllProducts();
}, [])
return (
<div>
<h1 className="pageTitle">All Products</h1>
<div className="all">
{content && content.map((c) =>
<SingleContent
key={c.id}
id={c.ID}
name={c.Name}
sku={c.SKU}
category={c.Category}/> )}
</div>
</div>
)
}
Inside fetchAllProducts() you could map the data.Products array you get from the first request, call the second api for each item and add the product image to the item.
Then you can update the contents with the resulting array.
Edited: example code below.
const fetchAllProducts = async () => {
const { data } = await axios.get('https://inventory.dearsystems.com/ExternalApi/v2/Product',{
headers: {
"api-auth-accountid": process.env.REACT_APP_API_ID,
"api-auth-applicationkey": process.env.REACT_APP_API_KEY
}
});
const productsWithImage = data.Products
.map(async product => {
const imageUrl = await axios.get("https://inventory.dearsystems.com/ExternalApi/v2/product/attachments?ProductID=" + product.id)
return {...product, imageUrl }
})
setContent(productsWithImage)
}
// Then you can use product.imageUrl when you map your products
Use for instead of map because it was returning a Promise. The problem is that if setContent(result) is called outside of the for, it only returns on register.
See the code:
export const AllHandle = () => {
const [content, setContent] = useState([]);
const fetchAllProducts = async () => {
const { data } = await axios.get("https://inventory.dearsystems.com/ExternalApi/v2/Product?limit=10",{
headers: {
"api-auth-accountid": process.env.REACT_APP_API_ID,
"api-auth-applicationkey": process.env.REACT_APP_API_KEY
}
});
let result = [];
const totaProducts = await data.Products;
for (let product of totaProducts) {
const imageUrl = await axios.get(`https://inventory.dearsystems.com/ExternalApi/v2/product/attachments?ProductID=${product.ID}`, {
headers: {
"api-auth-accountid": process.env.REACT_APP_API_ID,
"api-auth-applicationkey": process.env.REACT_APP_API_KEY
}
});
const imgUrl = imageUrl.data
result = [{ ...product, imgUrl}]
}
setContent(result)
}
useEffect(() =>{
fetchAllProducts();
}, [])
return (
<div>
<h1 className="pageTitle">All Products</h1>
<div className="all">
{content && content.map((c) =>
<SingleContent
key={c.ID}
id={c.ID}
name={c.Name}
sku={c.SKU}
category={c.Category}
attachment= { c.imgUrl[0].DownloadUrl}
/>
)}
</div>
</div>
)
}
Related
I am trying to add a recipe to my favourites list but only if it's not in the list already.
I tried to fetch the favourites array and check for the same id, but it's not working. It doesn't take the array. When I console.log the array there is nothing. Please any help.
Here is the RecipeModel logic
import "./RecipeModel.css";
import { Link, NavLink, useNavigate, useParams } from 'react-router-dom';
import React, { useLayoutEffect, useState,useEffect, useContext } from 'react';
import * as userService from '../../../services/userService';
import { AuthContext } from "../../../contexts/AuthContext";
import * as likeService from '../../../services/likeService';
import useRecipeState from "../../EditRecipe/RecipeState";
const RecipeModel = ({recipe}) => {
const history = useNavigate();
const {user} = useContext(AuthContext);
const {recipeId} = useParams();
const [likes,setLikes] = useRecipeState(recipeId);
const [favourites,setFavourites] = useState([]);
useEffect(() => {
likeService.getLikes(recipe._id)
.then(likes => {
setLikes(state => ({...state, likes}))
})
}, []);
useEffect(() => {
userService.yourFavourites(user._id)
.then(result => {
setFavourites(result);
})
},[]);
const valid = !(favourites.some(i => i._id === recipe._id));
if(valid) {
const HandleFavourite = (e) => {
e.preventDefault();
console.log(`Recipe ${recipe._id}`);
const name = recipe.name;
const time = recipe.time;
const imageUrl = recipe.imageUrl;
const ingredients = recipe.ingredients;
const instructions = recipe.instructions;
userService.addFavourite({
name,
time,
imageUrl,
ingredients,
instructions
},user.accessToken)
.then(result => {
console.log(result);
console.log(index);
console.log(user._id);
history('/favourites');
})
}
}
const likeButtonClick = () => {
if (user._id === recipe._ownerId) {
return;
}
if (recipel.likes.includes(user._id)) {
return;
}
likeService.like(user._id, recipeId)
.then(() => {
setLikes(state => ({...state, likes: [...state.likes, user._id]}));
console.log('liked');
});
};
return (
<article className="articles">
<img className="img2" src={recipe.imageUrl}/>
<h1>{recipe.name}</h1>
<p className="cut-text">{recipe.instructions}</p>
<div className="btns1">
<Link smooth= "true" className="btnd" to={`/recipe-details/recipe-number:${recipe._id}`}>Details</Link>
<button className="like" onClick={likeButtonClick} > <i className="fas fa-solid fa-thumbs-up"></i> {likes.likes?.length || 0}</button>
<button className="favour" onClick={HandleFavourite} ><i className="fas fa-solid fa-heart-circle-plus"></i></button>
</div>
</article>
);
};
export default RecipeModel;
Thats the userService logic :
export const addFavourite = async (recipeData,token) => {
let response = await fetch(`${baseUrl}/favourites`, {
method: 'POST',
headers: {
'content-type': 'application/json',
'X-Authorization': token,
},
body: JSON.stringify(recipeData)
});
let result = await response.json();
return result;
};
export const getAllFavourites = async () => {
let response = await fetch(`${baseUrl}/favourites`)
let recipes = await response.json();
let result = Object.values(recipes);
return result;
}
export const removeFavourite = (recipeId, token) => {
return fetch(`${baseUrl}/favourites/${recipeId}`, {
method: 'DELETE',
headers: {
'X-Authorization': token,
},
}).then(res => res.json());
};
export const getOneFav = (recipeId) => {
return fetch(`${baseUrl}/favourites/${recipeId}`)
.then(res => res.json())
};
export const yourFavourites = (ownerId) => {
let query = encodeURIComponent(`_ownerId="${ownerId}"`);
return request.get(`${baseUrl}/favourites?where=${query}`);
};
import { useState, useEffect } from 'react';
import axios from 'axios'
import { Loading } from './loading';
function News({ pageSize }) {
const [isLoading, setIsLoading] = useState(false)
const [state, setState] = useState({
article: [],
page: 1
}
)
const getUsers = async () => {
setIsLoading(true)
let res = await axios.get(`https://newsapi.org/v2/everything?domains=wsj.com&apiKey=79b02b430c1946cd9c505d3f91d7aec6&page=1&pageSize=${pageSize}`);
setState({article: res.data.articles})
setIsLoading(false)
};
useEffect(() => {
getUsers()
}, [])
const handleNext = async () => {
setIsLoading(true)
let res = await axios.get(`https://newsapi.org/v2/everything?domains=wsj.com&apiKey=79b02b430c1946cd9c505d3f91d7aec6&page=${state.page + 1}&pageSize=${pageSize}`);
setState({article: res.data.articles, page: state.page + 1})
setIsLoading(false)
}
let data = Array.from(state.article)
return (
<div>
<h2>News</h2>
<button onClick={handleNext}>Next</button>
{isLoading && <Loading />}
{!isLoading && data.map((elements) => {
return (
<div key={elements.url} style={{ marginBottom: '2rem' }}>
<div> {elements.description} </div>
<div>{new Date(elements.publishedAt).toGMTString()}</div>
</div>
)
})}
</div>
);
}
export default News;
When I take states separately for data and page, I'm able to display next page's data. But now that I've created one state to manage multiple objects, it displays back first page's data instead of next page's data. I don't know what I'm doing wrong. Pls help me!
Ignore the redundancy.
Try this:
const getUsers = async () => {
setIsLoading(true)
let res = await axios.get(`https://newsapi.org/v2/everything?domains=wsj.com&apiKey=79b02b430c1946cd9c505d3f91d7aec6&page=1&pageSize=${pageSize}`);
setState({...state, article: res.data.articles})
setIsLoading(false)
};
I'm creating a page that will call my API route to return the value from my collection using MongoDB. But I'm having this error of Objects are not valid as a React child. I don't know why this happening. Can you please help me?
pages/index.js
export const getServerSideProps = async () => {
const res = await fetch('http://localhost:3000/api/listings');
const data = await res.json();
if (!data) {
return {
notFound: true,
};
}
return { props: { data } };
};
const index = async ({ data }) => {
return (
<>
<section className='w-screen h-screen bg-hero-pattern bg-cover bg-no-repeat bg-bottom'></section>
{data.map((prop) => (
<div key={prop._id}>
<h1>{prop.name}</h1>
<h2 className='text-2xl truncate'>{prop.summary}</h2>
<p>{prop.description}</p>
</div>
))}
</>
);
};
pages/api/listings
import { connectToDatabase } from '../../middlewares/mongodb';
export const fetchDbData = async () => {
const { db } = await connectToDatabase();
const data = await db
.collection('listingsAndReviews')
.find({})
.limit(1)
.toArray();
return JSON.parse(JSON.stringify(data));
};
export default async (req, res) => {
const data = await fetchDbData();
res.status(200).json(data);
};
I'm developing an ecommerce app with Firestore.
When a user deletes an item or adds an item - it's rendering properly.
But when I'm trying to empty the whole cart (delete doc), it's just not rendering without refresh.
Maybe it's about the deleted doc, so the the function cannot find the doc because there is no doc?
If so, what would be best practice solution here?
Here is the code:
import React, { useState, useEffect } from 'react'
import firebase from 'firebase';
import { useAuth, useStoreUpdate } from '../contexts/FirebaseContext';
import { Link, useHistory } from 'react-router-dom';
import 'react-responsive-modal/styles.css';
import { Modal } from 'react-responsive-modal';
export default function Cart() {
const [userMail, setUserMail] = useState(undefined)
const [userCart, setUserCart] = useState(undefined)
const [totalAmmout, setTotalAmmout] = useState(0)
const user = useAuth()
const userDoc = firebase.firestore().collection("cart").doc(userMail)
const updateStore = useStoreUpdate()
const [open, setOpen] = useState(false);
const onOpenModal = () => setOpen(true);
const onCloseModal = () => setOpen(false);
const history = useHistory()
const emptyCart = async () => {
await userDoc.delete()
await updateCart()
await console.log('ksaljdklasd');
await updateStore()
await console.log('dasdsad');
}
const updateCart = () => {
userDoc.get().then((doc) => {
if (doc.exists) {
let cart = doc.data()
setUserCart(cart)
}
})
}
const updateData = async () => {
if (user.currentUser) {
await updateCart()
if (userCart) {
let totalPrice = 0;
await userCart.item.forEach(item => {
totalPrice += item.price
})
await setTotalAmmout(totalPrice)
}
}
}
async function removeFromCart(itemId, name, url, price, category, type, description) {
const cartItem = { itemId, name, url, price, category, type, description }
await userDoc.update({
item: firebase.firestore.FieldValue.arrayRemove(cartItem)
})
await updateCart()
await updateStore()
}
useEffect(() => {
if (user.currentUser) {
setUserMail(user.currentUser.email);
updateStore();
}
}, []);
useEffect(() => {
updateData().then(
console.log(totalAmmout)
)
}, userCart);
if (!userCart) return <h1>hold</h1>
return (
<main className="main-cart">
<div className="container">
{userCart.item && userCart.item.length >= 1 && userCart.item.map((item) => {
return (
< div className="item-container" key={item.itemId} >
<h3>{item.name}</h3>
<p>${item.price}</p>
<img height="150px" width="150px" src={item.url} alt="" />
<button onClick={async () => {
await removeFromCart(item.itemId, item.name, item.url, item.price, item.category, item.type, item.description)
}}>X</button>
</div>
)
})}
</div>
<button className="fixed-bottom-link" onClick={onOpenModal}>finish</button>
<Modal showCloseIcon={true} open={open} onClose={onCloseModal} center>
<div className="modal-container">
<div>
{userCart &&
userCart.item.map(item => {
return (
<li>{item.name} <span className="strong">{'|$' + item.price}</span></li>
)
})
}
{totalAmmout &&
<h3>total price: ${totalAmmout}</h3>
}
</div>
<button onClick={emptyCart}>Click to Pay</button>
</div>
</Modal>
</main >
)
}
just had to reset the doc :
befor :
const emptyCart = async () => {
await userDoc.delete()
await updateCart()
await updateStore()
}
after :
const emptyCart = async () => {
const userDoc = await firebase.firestore().collection("cart").doc(userMail)
await userDoc.delete()
await userDoc.set({
item: firebase.firestore.FieldValue.arrayUnion()
})
await updateCart()
await updateStore()
}
I have problem with load data to component after click on button.
I use getInitialProps to first load data on page.
How to load new data and past them to {data} after click?
export default function Users({ data }) {
const fetchData = async () => {
const req = await fetch("https://randomuser.me/api/?gender=male&results=100");
const data = await req.json();
return { data: data.results };
};
const handleClick = (event) => {
event.preventDefault();
fetchData();
};
return (
<Layout>
<button onClick={handleClick}>FETCH DATA</button>
{data.map((user) => {
return (
<div>
{user.email}
<img src={user.picture.medium} alt="" />
</div>
);
})}
</Layout>
);
}
Users.getInitialProps = async () => {
const req = await fetch(
"https://randomuser.me/api/?gender=female&results=10"
);
const data = await req.json();
return { data: data.results };
};
Thank a lot for help!
Use useState with the default value being the data you initially retrieved via getInitialProps:
import { useState } from 'React';
export default function Users({ initialData }) {
const [data, setData] = useState(initialData);
const fetchData = async () => {
const req = await fetch('https://randomuser.me/api/?gender=male&results=100');
const newData = await req.json();
return setData(newData.results);
};
const handleClick = (event) => {
event.preventDefault();
fetchData();
};
return (
<Layout>
<button onClick={handleClick}>FETCH DATA</button>
{data.map((user) => {
return (
<div>
{user.email}
<img src={user.picture.medium} alt="" />
</div>
);
})}
</Layout>
);
}
Users.getInitialProps = async () => {
const req = await fetch('https://randomuser.me/api/?gender=female&results=10');
const data = await req.json();
return { initialData: data.results };
};
Sidenote: Times have changed and it would seem that user1665355 is indeed correct:
Recommended: getStaticProps or getServerSideProps
If you're using Next.js 9.3 or newer, we recommend that you use
getStaticProps or getServerSideProps instead of getInitialProps.
These new data fetching methods allow you to have a granular choice
between static generation and server-side rendering.
import { useState } from 'React';
export default function Users({ initialData }) {
const [data, setData] = useState(initialData);
const fetchData = async () => {
const req = await fetch('https://randomuser.me/api/?gender=male&results=100');
const newData = await req.json();
setData(newData.results);
};
const handleClick = (event) => {
event.preventDefault();
fetchData();
};
return (
<Layout>
<button onClick={handleClick}>FETCH DATA</button>
{data.map(user => {
return (
<div key={user.login.uuid}>
{user.email}
<img src={user.picture.medium} alt="" />
</div>
);
})}
</Layout>
);
}
Users.getInitialProps = async () => {
const req = await fetch('https://randomuser.me/api/?gender=female&results=10');
const data = await req.json();
return { initialData: data.results };
};
I would like to list my notes about George's code. At least, it should pay attention to them.
First of all, it should attach any key to a div element otherwise a warning will have appeared in the browser console. Here is an article about using keys: https://reactjs.org/docs/lists-and-keys.html#keys
As well, the keyword return can be removed from the fetchData function that doesn't return a response.
It is recommended to use getStaticProps or getServerSideProps now. https://nextjs.org/docs/api-reference/data-fetching/getInitialProps