shopping cart array not rendering properly, react.js - javascript

after a fetch if I click to some card I am able to populate an empty array.
I would like to pass it as a prop to a child component and I guess I am doing the right way, the problem occurs when within the children I am trying to console log it because I can not see any errors and the console.log is not printing anything
let shoppingCart = [];
const fetchProducts = async () => {
const data = await fetch(
"blablablablablab"
);
const products = await data.json();
setProducts(products);
console.log(products);
};
const handleShoppingCart = product => {
shoppingCart.push(product);
console.log(shoppingCart);
return shoppingCart;
};
Inside the return function I tried to check if the array was not empty, if was not undefined or if was not null but with the same result
{shoppingCart.length !== 0 ? (
<ShoppingCart parkingSlots={shoppingCart} />
) : null}
children component
const ShoppingCart = ({ parkingSlots }) => {
console.log(parkingSlots);
const parkingSlotsComponent = parkingSlots.map((parkingSlot, i) => {
// const { name } = parkingSlot;
return (
<div className="parking_details" key={i}>
{parkingSlot.name}
</div>
);
});
return <div className="checkout">{parkingSlotsComponent}</div>;
};

The data is in props.
When data is passed to child component via props, then it is part of props child component. Try below and see if you can console log the data.
const ShoppingCart = props => {
console.log(props.parkingSlots);
const parkingSlotsComponent = props.parkingSlots.map((parkingSlot, i) => {
// const { name } = parkingSlot;
return (
<div className="parking_details" key={i}>
{props.parkingSlot.name}
</div>
);
});
return <div className="checkout">{parkingSlotsComponent}</div>;
};

Related

How to delete an item in an array that is stored in the backend server?

Sorry I'm quite new to coding and I could not delete the item as clicking it would bring me to the page and error out. I tried to delete the item based on the product id but it doesn't work. When I refreshed the page, the item is still there.
The array in the server looks like that:
[{"id":1,"name":"Apple","price":2,"createdAt":"2022","updatedAt":"2022"},{"id":2,"name":"Orange","price":1,"createdAt":"2022","updatedAt":"2022"}]
import "./App.css";
import React from "react";
import AddProduct from "./Components/AddProduct";
import SingleProduct from "./Components/SingleProduct";
import axios from "axios";
import { useState, useEffect } from "react";
export default function App() {
const [openSingle, setOpenSingle] = useState(false);
const [products, setProducts] = useState([]);
const [currentId, setCurrentId] = useState("");
const getInitialData = async () => {
let initialAPICall = await axios.get(
`${process.env.REACT_APP_API_SERVER}/products`
);
setProducts(initialAPICall.data);
};
useEffect(() => {
getInitialData();
}, []);
const toggleView = (product) => {
setOpenSingle(!openSingle);
setCurrentId(product.id);
};
const createNewProduct = async (name, price) => {
let product = {
name,
price,
};
let response = await axios.post(
`${process.env.REACT_APP_API_SERVER}/products`,
product
);
let newArray = [...products];
newArray.push(response.data);
setProducts(newArray);
};
const deleteClick = (id) => {
var index = products
.map(function (item) {
return item.Id;
})
.indexOf(id);
products.splice(index, 1);
};
return (
<div className="App">
<header className="App-header">
{openSingle ? (
<div>
<SingleProduct toggle={toggleView} id={currentId} />
</div>
) : (
<div>
<h4>Supermarket</h4>
<h5>Products</h5>
<div className="container">
{products && products.length > 0 ? (
products.map((product) => (
<div
className="product"
key={product.id}
onClick={() => toggleView(product)}
>
<h4>{product.name}</h4>
<h5>${product.price}</h5>
<button onClick={deleteClick(product.id)}>Delete</button>
</div>
))
) : (
<p>Error</p>
)}
</div>
<AddProduct addProduct={createNewProduct} />
</div>
)}
</header>
</div>
);
}
My controller.js:
const BaseController = require("./baseController");
class ProductsController extends BaseController {
constructor(model) {
super(model);
}
async insertOne(req, res) {
const { name, price } = req.body;
try {
const newProduct = await this.model.create({
updated_at: new Date(),
created_at: new Date(),
name: name,
price: price,
});
return res.json(newProduct);
} catch (err) {
return res.status(400).json({ error: true, msg: err });
}
}
async getOne(req, res) {
const id = req.params.productId;
try {
const output = await this.model.findByPk(id);
return res.json(output);
} catch (err) {
console.log(err);
return res.status(400).json({ error: true, msg: err });
}
}
}
module.exports = ProductsController;
How do I delete an item in this case? Thank you.
To do this you will have to create a route on your express server that handles the deletion of an element in the array.This route uses the 'POST' method to send to the server the name of the item to remove from the array.
The on the server you find will check to see if an item that matches the one sent is present in the array and deletes it. For this you can use forEach to find the item and remove it from the array.
myArray.forEach((item,index) => {
if(item === itemToDelete){
myArray.splice(index, 1);
})
unfortunately I'm not able to go through all the code but in the first component at in the deleteClick function:
const deleteClick = (id) => {
var index = products
.map(function (item) {
return item.Id;
})
.indexOf(id);
products.splice(index, 1);};
you seem be trying to remove the item from the array on the client. The right way would be to call your backend route for removing items on the server side using axios to make the call and sending the id of the item. Since the backend has direct access to your database (the way to remove the item will depend on the database you are using) or array on the server (here the method is similar to what the snipped i took from your code or my first answer) after this operation the your backend should send the updated array of using "res.json"
this new array should then be recieved on the frontend and stored in your state that way changes made to it will be able to be reflected in the UI.

How can I display the results of map function in jsx?

I'm slowly learning react and trying to display the results of my searchMap function (movie title/poster) with the TMDB API. I can log the information I need to the console, but I get undefined variables and other errors when trying to display the information in the commented div.
https://codesandbox.io/s/ddmdu4
function App() {
const search = async (event) => {
const searchQuery = event.target.value;
if (searchQuery) {
const searchReq = await fetch(
`https://api.themoviedb.org/3/search/movie?api_key=${process.env.API_KEY}&query=${searchQuery}`
).then((res) => res.json());
const searchResults = searchReq.results;
searchMap(searchResults);
}
};
const searchMap = (searchResults) => {
searchResults.map((movie) => {
console.log(`${movie.title}`);
console.log(`${movie.backdrop_path}`);
});
};
return (
<div className="App">
<div>
<input type="text" onChange={search} placeholder="Search"></input>
</div>
<div>{/* Display movie title/poster*/}</div>
</div>
);
}
export default App;
Since you want to update the DOM each time the result changes I would recommend using that inside of a state like so:
const [searchResults, setSearchResults] = React.useState([]);
In your async search function update the state by using its appropiate "setter":
.then((res) => res.json());
setSearchResults(searchReq.results);
And inside your return you can map the result as follows:
<div>
{searchResults.map((movie) => (
<>
<div>{movie.title}</div>
<div>{movie.backdrop_path}</div>
</>
))}
</div>

Cannot read property 'map' of undefined [React.js]

so when i do my login and i try to redirect to this page it appears me that error it must be something with useEffect i dont know
here is my code
useEffect(() => {
let canUpdate = true;
getVets().then((result) => canUpdate && setVets(result));
return function cleanup() {
canUpdate = false;
};
}, []);
const getVets = async () => {
const url = 'http://localhost:8080/all/vet';
const response = await fetch(url);
const data = await response.json();
setVets(data);
};
// const { appointmentType, animalID, room, hora, notes } = this.state;
return (
<React.Fragment>
<div class='title'>
<h5>2 médicos vetenários disponíveis</h5>
</div>
<div>
{vets.map((data) => (
<ObterMedicos
key={data.name}
name={data.name}
specialty={data.specialty}
/>
))}
</div>
</React.Fragment>
);
}
vets might not have data on the first render and when the code tries to execute map operation on it, it gets undefined.map, which is not allowed.
You can either set vets to empty array at the time of defining the state
const [vets,setVets] = useState([]);
or just check on vets using Optional chaning (?) before using the map function:
{vets?.map((data) => (
<ObterMedicos
key={data.name}
name={data.name}
specialty={data.specialty}
/>
))}

How do I call a function within another function when the data I need is in the global scope?

I have a set of card objects that I map over.
When I click on a card it adds the selected class which in turn gives it a border to show the user it is selected, it also adds the id of the card to the selectedCards useState array.
WHAT I WANT TO HAPPEN:
Each card object has a creditAvailable key state which is equal to a figure.
On selection (click) of the card, in addition to selecting the card I would also like to add up the creditAvailable and display it on the screen. and when I unselect the card I would like the figure to go down.
WHAT I HAVE TRIED:
I thought it would be as simple as calling the function to add up the credit inside the first function which selects the card, however when console logging inside the first function I see that the state has not yet updated. (scope).
I then tried to call the function outside of the first function but it gave me an infinite loop. Here is my code.
Any ideas? Thanks
const [cards, setCards] = useState([]);
const [selectedCards, setSelectedCards] = useState([]);
const [total, setTotal] = useState();
const handleSelectCard = (id) => {
if (selectedCards.includes(id)) {
const filteredIds = selectedCards.filter((c) => c !== id);
setSelectedCards([...filteredIds]);
} else {
setSelectedCards([...selectedCards, id]);
}
// addUpCreditAvailable(); // nothing happens
console.log(selectedCards); // []
};
console.log(selectedCards) // [1] for example. This is in the global scope
const addUpCreditAvailable = () => {
console.log("inside add up credit");
const chosenCards = selectedCards.map((id) => {
const foundCard = allCards.find((card) => {
return card.id === id;
});
return foundCard;
});
const result = chosenCards.reduce((acc, card) => {
return acc + card.creditAvailable;
}, 0);
setTotal(result);
return result;
};
return (
<div className="Container">
<UserInputForm submitData={handleSubmitData} />
<h1> Cards available to you displayed are below!</h1>
{cards.map(
({
id,
name,
number,
apr,
balanceTransfer,
purchaseDuration,
creditAvailable,
expiry,
}) => (
<CreditCard
key={id}
name={name}
number={number}
apr={apr}
balanceTransferDuration={balanceTransfer}
purchaseOfferDuration={purchaseDuration}
creditAvailable={creditAvailable}
expiry={expiry}
onClickCard={() => handleSelectCard(id)}
selected={selectedCards.includes(id)}
/>
)
)}
<span> £{total}</span>
)}
I figured it out with the help from above. As Wilms said i had to return the result of the handleSelectCard function and return the result of the addUpCredit function. Then I called the addUpCreditAvailable with the selectedCards state and stored the result in a variable which i then displayed in my render method.
const [cards, setCards] = useState([]);
const [selectedCards, setSelectedCards] = useState([]);
const handleSelectCard = (id) => {
if (selectedCards.includes(id)) {
const filteredIds = selectedCards.filter((c) => c !== id);
setSelectedCards([...filteredIds]);
} else {
setSelectedCards([...selectedCards, id]);
}
return selectedCards;
};
const addUpCreditAvailable = (selectedCards) => {
const chosenCards = selectedCards.map((id) => {
const foundCard = allCards.find((card) => {
return card.id === id;
});
return foundCard;
});
const result = chosenCards.reduce((acc, card) => {
return acc + card.creditAvailable;
}, 0);
return result;
};
const totalCredit = addUpCreditAvailable(selectedCards);
render method:
render (
[...]
{selectedCards.length && (
<div className={bem(baseClass, "total-credit")}>
Total Credit available: £{totalCredit}
</div>
)}
[...]
)

Object value is undefined but it's there React

I have the following code :
export default function ProjectView({filteredProjects,revenueGroups}) {
const [projects,setProjects] = useState();
useEffect(() => {
const aap = filteredProjects.map(filteredObject => {
getProjectFields(filteredObject.projectId).then(res => {
filteredObject.rekt = res.data[0].id;
})
return filteredObject;
})
setProjects(aap);
},[filteredProjects])
And the rendered component :
return (
<div className='main'>
{projects.map(project => (
<div className='view-container' key={project._id}>
{console.log(project)}
</div>
))}
</div>
)
This works fine , when i console.log(project) like above it shows the following :
{
projectName: "privaye"
rekt: "project:1b1126ebb28a2154feaad60b7a7437df"
__proto__: Object
}
when i console.log(projectName) it shows the name, but when i console.log(project.rekt) it's undefined...
eventhough its there when i console.log(project)
EDITED
I didn't notice the was a promise inside :P
useEffect(() => {
fetchThings()
},[filteredProjects])
const fetchThings = async () => {
const promArr = filteredProjects.map(filteredObject => {
return getProjectFields(filteredProject.project.id)
})
const filteredObjects = await Promise.all(promArr)
const projectsMod = filteredObjects.map(fo => ({
...fo,
rekt: fo.data[0].id,
}))
}
Maybe an approach like this will help you with the asyncronous problem
console.log isn't rendering anything so maybe React doesn't try to refresh this part of the DOM when projects state is updated.
You can stringify the object to check the content of the variable inside the return
return (
<div className='main'>
{projects.map(project => (
<div className='view-container' key={project._id}>
<span>{ JSON.stringify(project) }</span>
</div>
))}
</div>
)
You are running promise, after this promise will return value you set rekt, but promise will work god knows when, and most probably you check value before this promise resolved.
getProjectFields(filteredObject.projectId).then(res => {
// THIS CODE CAN RUN AFTER RENDERING
filteredObject.rekt = res.data[0].id;
})
so first you wait till promises will complete and only then set new state
const ourPreciousPromises = filteredProjects.map(filteredObject =>
getProjectFields(filteredObject.projectId).then(res => {
filteredObject.rekt = res.data[0].id;
return {...filteredObject}
})
})
Promise.all(ourPreciousPromises).then(newObjects =>
setProjects(newObjects)
)

Categories

Resources